public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
* [PATCH] IntelSiliconPkg/VTd: Use 256-bit invaildation queue descriptor
@ 2022-11-21  5:43 Sheng Wei
  0 siblings, 0 replies; 2+ messages in thread
From: Sheng Wei @ 2022-11-21  5:43 UTC (permalink / raw)
  To: devel; +Cc: Ray Ni, Rangasai V Chaganty, Jenny Huang, Robert Kowalewski

256-bit invaildation queue descriptor could be used for both
abort DMA mode and legacy mode.

Change-Id: Ib3b94d6c5782d42c53056204312f6f4ad513344e
Signed-off-by: Sheng Wei <w.sheng@intel.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Rangasai V Chaganty <rangasai.v.chaganty@intel.com>
Cc: Jenny Huang <jenny.huang@intel.com>
Cc: Robert Kowalewski <robert.kowalewski@intel.com>
---
 .../VTd/IntelVTdDmarPei/IntelVTdDmar.c        | 172 ++++++++-----
 .../VTd/IntelVTdDmarPei/IntelVTdDmarPei.h     |   5 +-
 .../Feature/VTd/IntelVTdDxe/DmaProtection.c   |   3 +
 .../Feature/VTd/IntelVTdDxe/DmaProtection.h   |   5 +-
 .../Feature/VTd/IntelVTdDxe/VtdReg.c          | 232 +++++++++++-------
 .../Include/IndustryStandard/Vtd.h            |  65 ++++-
 6 files changed, 329 insertions(+), 153 deletions(-)

diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDmarPei/IntelVTdDmar.c b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDmarPei/IntelVTdDmar.c
index af85a3d8e..87d5edaa6 100644
--- a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDmarPei/IntelVTdDmar.c
+++ b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDmarPei/IntelVTdDmar.c
@@ -79,10 +79,11 @@ PerpareCacheInvalidationInterface (
   IN VTD_UNIT_INFO *VTdUnitInfo
   )
 {
-  UINT16         QueueSize;
-  UINT64         Reg64;
+  UINT8          DescriptorWidth;
+  UINTN          QueueSize;
   UINT32         Reg32;
   VTD_ECAP_REG   ECapReg;
+  VTD_IQA_REG    IqaReg;
   UINTN          VtdUnitBaseAddress;
 
   VtdUnitBaseAddress = VTdUnitInfo->VtdUnitBaseAddress;
@@ -121,20 +122,32 @@ PerpareCacheInvalidationInterface (
   //
   // Setup the IQ address, size and descriptor width through the Invalidation Queue Address Register
   //
-  if (VTdUnitInfo->QiDesc == NULL) {
+  if (VTdUnitInfo->QiDescBuffer == NULL) {
+    //
+    // It uses 256-bit descriptor
+    // Queue size is 128.
+    //
+    DescriptorWidth = 1;
     QueueSize = 0;
-    VTdUnitInfo->QiDescLength = 1 << (QueueSize + 8);
-    VTdUnitInfo->QiDesc = (QI_DESC *) AllocatePages (EFI_SIZE_TO_PAGES (sizeof (QI_DESC) * VTdUnitInfo->QiDescLength));
-    if (VTdUnitInfo->QiDesc == NULL) {
+
+    VTdUnitInfo->QiDescBufferSize = (sizeof (QI_256_DESC) * ((UINTN) 1 << (QueueSize + 7)));
+    VTdUnitInfo->QiDescBuffer = AllocatePages (EFI_SIZE_TO_PAGES (VTdUnitInfo->QiDescBufferSize));
+    if (VTdUnitInfo->QiDescBuffer == NULL) {
       DEBUG ((DEBUG_ERROR,"Could not Alloc Invalidation Queue Buffer.\n"));
       return EFI_OUT_OF_RESOURCES;
     }
   }
 
-  DEBUG ((DEBUG_INFO, "Invalidation Queue Length : %d\n", VTdUnitInfo->QiDescLength));
-  Reg64 = (UINT64) (UINTN) VTdUnitInfo->QiDesc;
-  Reg64 |= QueueSize;
-  MmioWrite64 (VtdUnitBaseAddress + R_IQA_REG, Reg64);
+  DEBUG ((DEBUG_INFO, "Invalidation Queue Buffer Size : %d\n", VTdUnitInfo->QiDescBufferSize));
+  //
+  // 4KB Aligned address
+  //
+  IqaReg.Uint64 = (UINT64) (UINTN) VTdUnitInfo->QiDescBuffer;
+  IqaReg.Bits.DW = DescriptorWidth;
+  IqaReg.Bits.QS = QueueSize;
+  MmioWrite64 (VtdUnitBaseAddress + R_IQA_REG, IqaReg.Uint64);
+  IqaReg.Uint64 = MmioRead64 (VtdUnitBaseAddress + R_IQA_REG);
+  DEBUG ((DEBUG_INFO, "IQA_REG [0x%x]\n", IqaReg.Uint64));
 
   //
   // Enable the queued invalidation interface through the Global Command Register.
@@ -148,8 +161,6 @@ PerpareCacheInvalidationInterface (
     Reg32 = MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG);
   } while ((Reg32 & B_GSTS_REG_QIES) == 0);
 
-  VTdUnitInfo->QiFreeHead = 0;
-
   return EFI_SUCCESS;
 }
 
@@ -174,10 +185,10 @@ DisableQueuedInvalidationInterface (
       Reg32 = MmioRead32 (VTdUnitInfo->VtdUnitBaseAddress + R_GSTS_REG);
     } while ((Reg32 & B_GSTS_REG_QIES) != 0);
 
-    if (VTdUnitInfo->QiDesc != NULL) {
-      FreePages(VTdUnitInfo->QiDesc, EFI_SIZE_TO_PAGES (sizeof (QI_DESC) * VTdUnitInfo->QiDescLength));
-      VTdUnitInfo->QiDesc = NULL;
-      VTdUnitInfo->QiDescLength = 0;
+    if (VTdUnitInfo->QiDescBuffer != NULL) {
+      FreePages(VTdUnitInfo->QiDescBuffer, EFI_SIZE_TO_PAGES (VTdUnitInfo->QiDescBufferSize));
+      VTdUnitInfo->QiDescBuffer = NULL;
+      VTdUnitInfo->QiDescBufferSize = 0;
     }
 
     VTdUnitInfo->EnableQueuedInvalidation = 0;
@@ -197,12 +208,15 @@ QueuedInvalidationCheckFault (
   IN VTD_UNIT_INFO *VTdUnitInfo
   )
 {
-  UINT32     FaultReg;
+  UINT32            FaultReg;
+  VTD_IQERCD_REG    IqercdReg;
 
   FaultReg = MmioRead32 (VTdUnitInfo->VtdUnitBaseAddress + R_FSTS_REG);
   if (FaultReg & (B_FSTS_REG_IQE | B_FSTS_REG_ITE | B_FSTS_REG_ICE)) {
-    DEBUG((DEBUG_ERROR, "Detect Queue Invalidation Error [0x%08x]\n", FaultReg));
-    FaultReg |= (B_FSTS_REG_IQE | B_FSTS_REG_ITE | B_FSTS_REG_ICE);
+    IqercdReg.Uint64 = MmioRead64 (VTdUnitInfo->VtdUnitBaseAddress + R_IQERCD_REG);
+
+    DEBUG((DEBUG_ERROR, "Detect Queue Invalidation Error [0x%08x] - IQERCD [0x%016lx]\n", FaultReg, IqercdReg.Uint64));
+
     MmioWrite32 (VTdUnitInfo->VtdUnitBaseAddress + R_FSTS_REG, FaultReg);
     return RETURN_DEVICE_ERROR;
   }
@@ -223,37 +237,82 @@ QueuedInvalidationCheckFault (
 **/
 EFI_STATUS
 SubmitQueuedInvalidationDescriptor (
-  IN VTD_UNIT_INFO *VTdUnitInfo,
-  IN QI_DESC       *Desc
+  IN VTD_UNIT_INFO     *VTdUnitInfo,
+  IN QI_256_DESC       *Desc
   )
 {
-  EFI_STATUS Status;
-  UINT16     QiDescLength;
-  QI_DESC    *BaseDesc;
-  UINT64     Reg64Iqt;
-  UINT64     Reg64Iqh;
+  EFI_STATUS     Status;
+  UINTN          VtdUnitBaseAddress;
+  UINTN          QueueSize;
+  UINTN          QueueTail;
+  UINTN          QueueHead;
+  QI_DESC        *Qi128Desc;
+  QI_256_DESC    *Qi256Desc;
+  VTD_IQA_REG    IqaReg;
+  VTD_IQT_REG    IqtReg;
+  VTD_IQH_REG    IqhReg;
 
   if (Desc == NULL) {
     return EFI_INVALID_PARAMETER;
   }
 
-  QiDescLength = VTdUnitInfo->QiDescLength;
-  BaseDesc = VTdUnitInfo->QiDesc;
-
-  DEBUG((DEBUG_INFO, "[0x%x] Submit QI Descriptor [0x%016lx, 0x%016lx]\n", VTdUnitInfo->VtdUnitBaseAddress, Desc->Low, Desc->High));
-
-  BaseDesc[VTdUnitInfo->QiFreeHead].Low = Desc->Low;
-  BaseDesc[VTdUnitInfo->QiFreeHead].High = Desc->High;
-  FlushPageTableMemory(VTdUnitInfo, (UINTN) &BaseDesc[VTdUnitInfo->QiFreeHead], sizeof(QI_DESC));
+  VtdUnitBaseAddress = VTdUnitInfo->VtdUnitBaseAddress;
+  IqaReg.Uint64 = MmioRead64 (VtdUnitBaseAddress + R_IQA_REG);
+  if (IqaReg.Bits.IQA == 0) {
+    return EFI_NOT_READY;
+  }
+  IqtReg.Uint64 = MmioRead64 (VtdUnitBaseAddress + R_IQT_REG);
 
-  DEBUG((DEBUG_INFO,"QI Free Head=0x%x\n", VTdUnitInfo->QiFreeHead));
-  VTdUnitInfo->QiFreeHead = (VTdUnitInfo->QiFreeHead + 1) % QiDescLength;
+  if (IqaReg.Bits.DW == 0) {
+    //
+    // 128-bit descriptor
+    //
+    QueueSize = (UINTN) (1 << (IqaReg.Bits.QS + 8));
+    Qi128Desc = (QI_DESC *) (UINTN) (IqaReg.Bits.IQA << VTD_PAGE_SHIFT);
+    QueueTail = (UINTN) IqtReg.Bits128Desc.QT;
+    Qi128Desc += QueueTail;
+    Qi128Desc->Low = Desc->Uint64[0];
+    Qi128Desc->High = Desc->Uint64[1];
+    FlushPageTableMemory (VTdUnitInfo, (UINTN) Qi128Desc, sizeof(QI_DESC));
+    QueueTail = (QueueTail + 1) % QueueSize;
+
+    DEBUG ((DEBUG_INFO, "[0x%x] Submit QI Descriptor 0x%x [0x%016lx, 0x%016lx]\n",
+            VtdUnitBaseAddress,
+            QueueTail,
+            Desc->Uint64[0],
+            Desc->Uint64[1]));
+
+    IqtReg.Bits128Desc.QT = QueueTail;
+  } else {
+    //
+    // 256-bit descriptor
+    //
+    QueueSize = (UINTN) (1 << (IqaReg.Bits.QS + 7));
+    Qi256Desc = (QI_256_DESC *) (UINTN) (IqaReg.Bits.IQA << VTD_PAGE_SHIFT);
+    QueueTail = (UINTN) IqtReg.Bits256Desc.QT;
+    Qi256Desc += QueueTail;
+    Qi256Desc->Uint64[0] = Desc->Uint64[0];
+    Qi256Desc->Uint64[1] = Desc->Uint64[1];
+    Qi256Desc->Uint64[2] = Desc->Uint64[2];
+    Qi256Desc->Uint64[3] = Desc->Uint64[3];
+    FlushPageTableMemory (VTdUnitInfo, (UINTN) Qi256Desc, sizeof(QI_256_DESC));
+    QueueTail = (QueueTail + 1) % QueueSize;
+
+    DEBUG ((DEBUG_INFO, "[0x%x] Submit QI Descriptor 0x%x [0x%016lx, 0x%016lx, 0x%016lx, 0x%016lx]\n",
+            VtdUnitBaseAddress,
+            QueueTail,
+            Desc->Uint64[0],
+            Desc->Uint64[1],
+            Desc->Uint64[2],
+            Desc->Uint64[3]));
+
+    IqtReg.Bits256Desc.QT = QueueTail;
+  }
 
   //
   // Update the HW tail register indicating the presence of new descriptors.
   //
-  Reg64Iqt = VTdUnitInfo->QiFreeHead << DMAR_IQ_SHIFT;
-  MmioWrite64 (VTdUnitInfo->VtdUnitBaseAddress + R_IQT_REG, Reg64Iqt);
+  MmioWrite64 (VtdUnitBaseAddress + R_IQT_REG, IqtReg.Uint64);
 
   Status = EFI_SUCCESS;
   do {
@@ -263,10 +322,15 @@ SubmitQueuedInvalidationDescriptor (
       break;
     }
 
-    Reg64Iqh = MmioRead64 (VTdUnitInfo->VtdUnitBaseAddress + R_IQH_REG);
-  } while (Reg64Iqt != Reg64Iqh);
+    IqhReg.Uint64 = MmioRead64 (VtdUnitBaseAddress + R_IQH_REG);
+    if (IqaReg.Bits.DW == 0) {
+      QueueHead = (UINTN) IqhReg.Bits128Desc.QH;
+    } else {
+      QueueHead = (UINTN) IqhReg.Bits256Desc.QH;
+    }
+  } while (QueueTail != QueueHead);
 
-  DEBUG((DEBUG_ERROR,"SubmitQueuedInvalidationDescriptor end\n"));
+  DEBUG((DEBUG_INFO,"SubmitQueuedInvalidationDescriptor end\n"));
   return Status;
 }
 
@@ -281,7 +345,7 @@ InvalidateContextCache (
   )
 {
   UINT64                        Reg64;
-  QI_DESC                       QiDesc;
+  QI_256_DESC                   QiDesc;
 
   if (VTdUnitInfo->EnableQueuedInvalidation == 0) {
     //
@@ -304,8 +368,10 @@ InvalidateContextCache (
     //
     // Queued Invalidation
     //
-    QiDesc.Low = QI_CC_FM(0) | QI_CC_SID(0) | QI_CC_DID(0) | QI_CC_GRAN(1) | QI_CC_TYPE;
-    QiDesc.High = 0;
+    QiDesc.Uint64[0] = QI_CC_FM(0) | QI_CC_SID(0) | QI_CC_DID(0) | QI_CC_GRAN(1) | QI_CC_TYPE;
+    QiDesc.Uint64[1] = 0;
+    QiDesc.Uint64[2] = 0;
+    QiDesc.Uint64[3] = 0;
 
     return SubmitQueuedInvalidationDescriptor(VTdUnitInfo, &QiDesc);
   }
@@ -326,7 +392,7 @@ InvalidateIOTLB (
   UINT64                        Reg64;
   VTD_ECAP_REG                  ECapReg;
   VTD_CAP_REG                   CapReg;
-  QI_DESC                       QiDesc;
+  QI_256_DESC                   QiDesc;
 
   if (VTdUnitInfo->EnableQueuedInvalidation == 0) {
     //
@@ -352,8 +418,10 @@ InvalidateIOTLB (
     // Queued Invalidation
     //
     CapReg.Uint64 = MmioRead64 (VTdUnitInfo->VtdUnitBaseAddress + R_CAP_REG);
-    QiDesc.Low = QI_IOTLB_DID(0) | QI_IOTLB_DR(CAP_READ_DRAIN(CapReg.Uint64)) | QI_IOTLB_DW(CAP_WRITE_DRAIN(CapReg.Uint64)) | QI_IOTLB_GRAN(1) | QI_IOTLB_TYPE;
-    QiDesc.High = QI_IOTLB_ADDR(0) | QI_IOTLB_IH(0) | QI_IOTLB_AM(0);
+    QiDesc.Uint64[0] = QI_IOTLB_DID(0) | QI_IOTLB_DR(CAP_READ_DRAIN(CapReg.Uint64)) | QI_IOTLB_DW(CAP_WRITE_DRAIN(CapReg.Uint64)) | QI_IOTLB_GRAN(1) | QI_IOTLB_TYPE;
+    QiDesc.Uint64[1] = QI_IOTLB_ADDR(0) | QI_IOTLB_IH(0) | QI_IOTLB_AM(0);
+    QiDesc.Uint64[2] = 0;
+    QiDesc.Uint64[3] = 0;
 
     return SubmitQueuedInvalidationDescriptor(VTdUnitInfo, &QiDesc);
   }
@@ -451,11 +519,6 @@ EnableDmarPreMem (
   Reg32 = MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG);
   DEBUG ((DEBUG_INFO, "EnableDmarPreMem: R_GSTS_REG = 0x%x \n", Reg32));
 
-  //
-  // Init DMAr Fault Event and Data registers
-  //
-  Reg32 = MmioRead32 (VtdUnitBaseAddress + R_FEDATA_REG);
-
   //
   // Write Buffer Flush
   //
@@ -525,11 +588,6 @@ EnableDmar (
   DEBUG ((DEBUG_INFO, "EnableDmar: waiting for RTPS bit to be set... \n"));
   SetGlobalCommandRegisterBits (VtdUnitBaseAddress, B_GMCD_REG_SRTP);
 
-  //
-  // Init DMAr Fault Event and Data registers
-  //
-  MmioRead32 (VtdUnitBaseAddress + R_FEDATA_REG);
-
   //
   // Write Buffer Flush before invalidation
   //
diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDmarPei/IntelVTdDmarPei.h b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDmarPei/IntelVTdDmarPei.h
index 5ade9ec35..4d4b912f2 100644
--- a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDmarPei/IntelVTdDmarPei.h
+++ b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDmarPei/IntelVTdDmarPei.h
@@ -21,9 +21,8 @@ typedef struct {
   VTD_ECAP_REG                     ECapReg;
   BOOLEAN                          Is5LevelPaging;
   UINT8                            EnableQueuedInvalidation;
-  UINT16                           QiDescLength;
-  QI_DESC                          *QiDesc;
-  UINT16                           QiFreeHead;
+  VOID                             *QiDescBuffer;
+  UINTN                            QiDescBufferSize;
   UINTN                            FixedSecondLevelPagingEntry;
   UINTN                            RootEntryTable;
   UINTN                            ExtRootEntryTable;
diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/DmaProtection.c b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/DmaProtection.c
index 628565ee7..878c952b7 100644
--- a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/DmaProtection.c
+++ b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/DmaProtection.c
@@ -496,6 +496,9 @@ SetupVtd (
   if (EFI_ERROR (Status)) {
     return;
   }
+
+  DumpVtdIfError ();
+
   DEBUG ((DEBUG_INFO, "PrepareVtdConfig\n"));
   PrepareVtdConfig ();
 
diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/DmaProtection.h b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/DmaProtection.h
index 7dd29a243..e83ebff41 100644
--- a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/DmaProtection.h
+++ b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/DmaProtection.h
@@ -81,9 +81,8 @@ typedef struct {
   PCI_DEVICE_INFORMATION           PciDeviceInfo;
   BOOLEAN                          Is5LevelPaging;
   UINT8                            EnableQueuedInvalidation;
-  UINT16                           QiDescLength;
-  QI_DESC                          *QiDesc;
-  UINT16                           QiFreeHead;
+  VOID                             *QiDescBuffer;
+  UINTN                            QiDescBufferSize;
 } VTD_UNIT_INFORMATION;
 
 //
diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/VtdReg.c b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/VtdReg.c
index 8e834f4c4..7e45ac2d2 100644
--- a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/VtdReg.c
+++ b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/VtdReg.c
@@ -68,71 +68,87 @@ PerpareCacheInvalidationInterface (
   IN UINTN  VtdIndex
   )
 {
-  UINT16  QueueSize;
-  UINT64  Reg64;
-  UINT32  Reg32;
-
-  if (mVtdUnitInformation[VtdIndex].VerReg.Bits.Major <= 5) {
-    mVtdUnitInformation[VtdIndex].EnableQueuedInvalidation = 0;
+  UINT8                 DescriptorWidth;
+  UINTN                 QueueSize;
+  UINT32                Reg32;
+  VTD_IQA_REG           IqaReg;
+  VTD_UNIT_INFORMATION  *VTdUnitInfo;
+  UINTN                 VtdUnitBaseAddress;
+
+  VTdUnitInfo = &mVtdUnitInformation[VtdIndex];
+  VtdUnitBaseAddress = VTdUnitInfo->VtdUnitBaseAddress;
+
+  if (VTdUnitInfo->VerReg.Bits.Major <= 5) {
+    VTdUnitInfo->EnableQueuedInvalidation = 0;
     DEBUG ((DEBUG_INFO, "Use Register-based Invalidation Interface for engine [%d]\n", VtdIndex));
     return EFI_SUCCESS;
   }
 
-  if (mVtdUnitInformation[VtdIndex].ECapReg.Bits.QI == 0) {
+  if (VTdUnitInfo->ECapReg.Bits.QI == 0) {
     DEBUG ((DEBUG_ERROR, "Hardware does not support queued invalidations interface for engine [%d]\n", VtdIndex));
     return EFI_UNSUPPORTED;
   }
 
-  mVtdUnitInformation[VtdIndex].EnableQueuedInvalidation = 1;
+  VTdUnitInfo->EnableQueuedInvalidation = 1;
   DEBUG ((DEBUG_INFO, "Use Queued Invalidation Interface for engine [%d]\n", VtdIndex));
 
-  Reg32 = MmioRead32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_GSTS_REG);
+  Reg32 = MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG);
   if ((Reg32 & B_GSTS_REG_QIES) != 0) {
     DEBUG ((DEBUG_ERROR,"Queued Invalidation Interface was enabled.\n"));
     Reg32 &= (~B_GSTS_REG_QIES);
-    MmioWrite32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_GCMD_REG, Reg32);
+    MmioWrite32 (VtdUnitBaseAddress + R_GCMD_REG, Reg32);
     do {
-      Reg32 = MmioRead32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_GSTS_REG);
+      Reg32 = MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG);
     } while ((Reg32 & B_GSTS_REG_QIES) != 0);
   }
 
   //
   // Initialize the Invalidation Queue Tail Register to zero.
   //
-  MmioWrite64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_IQT_REG, 0);
+  MmioWrite64 (VtdUnitBaseAddress + R_IQT_REG, 0);
 
   //
   // Setup the IQ address, size and descriptor width through the Invalidation Queue Address Register
   //
-  QueueSize = 0;
-  mVtdUnitInformation[VtdIndex].QiDescLength = 1 << (QueueSize + 8);
-  mVtdUnitInformation[VtdIndex].QiDesc = (QI_DESC *) AllocatePages (EFI_SIZE_TO_PAGES(sizeof(QI_DESC) * mVtdUnitInformation[VtdIndex].QiDescLength));
-
-  if (mVtdUnitInformation[VtdIndex].QiDesc == NULL) {
-    mVtdUnitInformation[VtdIndex].QiDescLength = 0;
-    DEBUG ((DEBUG_ERROR,"Could not Alloc Invalidation Queue Buffer.\n"));
-    return EFI_OUT_OF_RESOURCES;
+  if (VTdUnitInfo->QiDescBuffer == NULL) {
+    //
+    // It uses 256-bit descriptor
+    // Queue size is 128.
+    //
+    DescriptorWidth = 1;
+    QueueSize = 0;
+
+    VTdUnitInfo->QiDescBufferSize = (sizeof (QI_256_DESC) * ((UINTN) 1 << (QueueSize + 7)));
+    VTdUnitInfo->QiDescBuffer = AllocatePages (EFI_SIZE_TO_PAGES (VTdUnitInfo->QiDescBufferSize));
+    if (VTdUnitInfo->QiDescBuffer == NULL) {
+      DEBUG ((DEBUG_ERROR,"Could not Alloc Invalidation Queue Buffer.\n"));
+      return EFI_OUT_OF_RESOURCES;
+    }
   }
 
-  DEBUG ((DEBUG_INFO, "Invalidation Queue Length : %d\n", mVtdUnitInformation[VtdIndex].QiDescLength));
-  Reg64 = (UINT64)(UINTN)mVtdUnitInformation[VtdIndex].QiDesc;
-  Reg64 |= QueueSize;
-  MmioWrite64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_IQA_REG, Reg64);
+  DEBUG ((DEBUG_INFO, "Invalidation Queue Buffer Size : %d\n", VTdUnitInfo->QiDescBufferSize));
+  //
+  // 4KB Aligned address
+  //
+  IqaReg.Uint64 = (UINT64) (UINTN) VTdUnitInfo->QiDescBuffer;
+  IqaReg.Bits.DW = DescriptorWidth;
+  IqaReg.Bits.QS = QueueSize;
+  MmioWrite64 (VtdUnitBaseAddress + R_IQA_REG, IqaReg.Uint64);
+  IqaReg.Uint64 = MmioRead64 (VtdUnitBaseAddress + R_IQA_REG);
+  DEBUG ((DEBUG_INFO, "IQA_REG [0x%x]\n", IqaReg.Uint64));
 
   //
   // Enable the queued invalidation interface through the Global Command Register.
   // When enabled, hardware sets the QIES field in the Global Status Register.
   //
-  Reg32 = MmioRead32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_GSTS_REG);
+  Reg32 = MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG);
   Reg32 |= B_GMCD_REG_QIE;
-  MmioWrite32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_GCMD_REG, Reg32);
+  MmioWrite32 (VtdUnitBaseAddress + R_GCMD_REG, Reg32);
   DEBUG ((DEBUG_INFO, "Enable Queued Invalidation Interface. GCMD_REG = 0x%x\n", Reg32));
   do {
-    Reg32 = MmioRead32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_GSTS_REG);
+    Reg32 = MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG);
   } while ((Reg32 & B_GSTS_REG_QIES) == 0);
 
-  mVtdUnitInformation[VtdIndex].QiFreeHead = 0;
-
   return EFI_SUCCESS;
 }
 
@@ -146,21 +162,24 @@ DisableQueuedInvalidationInterface (
   IN UINTN  VtdIndex
   )
 {
-  UINT32  Reg32;
+  UINT32                Reg32;
+  VTD_UNIT_INFORMATION  *VTdUnitInfo;
 
-  if (mVtdUnitInformation[VtdIndex].EnableQueuedInvalidation != 0) {
-    Reg32 = MmioRead32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_GSTS_REG);
+  VTdUnitInfo = &mVtdUnitInformation[VtdIndex];
+
+  if (VTdUnitInfo->EnableQueuedInvalidation != 0) {
+    Reg32 = MmioRead32 (VTdUnitInfo->VtdUnitBaseAddress + R_GSTS_REG);
     Reg32 &= (~B_GMCD_REG_QIE);
-    MmioWrite32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_GCMD_REG, Reg32);
+    MmioWrite32 (VTdUnitInfo->VtdUnitBaseAddress + R_GCMD_REG, Reg32);
     DEBUG ((DEBUG_INFO, "Disable Queued Invalidation Interface. GCMD_REG = 0x%x\n", Reg32));
     do {
-      Reg32 = MmioRead32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_GSTS_REG);
+      Reg32 = MmioRead32 (VTdUnitInfo->VtdUnitBaseAddress + R_GSTS_REG);
     } while ((Reg32 & B_GSTS_REG_QIES) != 0);
 
-    if (mVtdUnitInformation[VtdIndex].QiDesc != NULL) {
-      FreePages(mVtdUnitInformation[VtdIndex].QiDesc, EFI_SIZE_TO_PAGES(sizeof(QI_DESC) * mVtdUnitInformation[VtdIndex].QiDescLength));
-      mVtdUnitInformation[VtdIndex].QiDesc = NULL;
-      mVtdUnitInformation[VtdIndex].QiDescLength = 0;
+    if (VTdUnitInfo->QiDescBuffer != NULL) {
+      FreePages(VTdUnitInfo->QiDescBuffer, EFI_SIZE_TO_PAGES (VTdUnitInfo->QiDescBufferSize));
+      VTdUnitInfo->QiDescBuffer = NULL;
+      VTdUnitInfo->QiDescBufferSize = 0;
     }
 
     mVtdUnitInformation[VtdIndex].EnableQueuedInvalidation = 0;
@@ -180,27 +199,16 @@ QueuedInvalidationCheckFault (
   IN UINTN  VtdIndex
   )
 {
-  UINT32     FaultReg;
+  UINT32            FaultReg;
+  VTD_IQERCD_REG    IqercdReg;
 
   FaultReg = MmioRead32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_FSTS_REG);
 
-  if (FaultReg & B_FSTS_REG_IQE) {
-    DEBUG((DEBUG_ERROR, "Detect Invalidation Queue Error [0x%08x]\n", FaultReg));
-    FaultReg |= B_FSTS_REG_IQE;
-    MmioWrite32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_FSTS_REG, FaultReg);
-    return RETURN_DEVICE_ERROR;
-  }
+  if (FaultReg & (B_FSTS_REG_IQE | B_FSTS_REG_ITE | B_FSTS_REG_ICE)) {
+    IqercdReg.Uint64 = MmioRead64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_IQERCD_REG);
 
-  if (FaultReg & B_FSTS_REG_ITE) {
-    DEBUG((DEBUG_ERROR, "Detect Invalidation Time-out Error [0x%08x]\n", FaultReg));
-    FaultReg |= B_FSTS_REG_ITE;
-    MmioWrite32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_FSTS_REG, FaultReg);
-    return RETURN_DEVICE_ERROR;
-  }
+    DEBUG((DEBUG_ERROR, "Detect Queue Invalidation Error [0x%08x] - IQERCD [0x%016lx]\n", FaultReg, IqercdReg.Uint64));
 
-  if (FaultReg & B_FSTS_REG_ICE) {
-    DEBUG((DEBUG_ERROR, "Detect Invalidation Completion Error [0x%08x]\n", FaultReg));
-    FaultReg |= B_FSTS_REG_ICE;
     MmioWrite32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_FSTS_REG, FaultReg);
     return RETURN_DEVICE_ERROR;
   }
@@ -221,36 +229,82 @@ QueuedInvalidationCheckFault (
 **/
 EFI_STATUS
 SubmitQueuedInvalidationDescriptor (
-  IN UINTN    VtdIndex,
-  IN QI_DESC  *Desc
+  IN UINTN        VtdIndex,
+  IN QI_256_DESC  *Desc
   )
 {
-  EFI_STATUS Status;
-  UINT16     QiDescLength;
-  QI_DESC    *BaseDesc;
-  UINT64     Reg64Iqt;
-  UINT64     Reg64Iqh;
+  EFI_STATUS     Status;
+  UINTN          VtdUnitBaseAddress;
+  UINTN          QueueSize;
+  UINTN          QueueTail;
+  UINTN          QueueHead;
+  QI_DESC        *Qi128Desc;
+  QI_256_DESC    *Qi256Desc;
+  VTD_IQA_REG    IqaReg;
+  VTD_IQT_REG    IqtReg;
+  VTD_IQH_REG    IqhReg;
 
   if (Desc == NULL) {
     return EFI_INVALID_PARAMETER;
   }
 
-  QiDescLength = mVtdUnitInformation[VtdIndex].QiDescLength;
-  BaseDesc = mVtdUnitInformation[VtdIndex].QiDesc;
-
-  DEBUG((DEBUG_VERBOSE, "[%d] Submit QI Descriptor [0x%08x, 0x%08x] Free Head (%d)\n", VtdIndex, Desc->Low, Desc->High, mVtdUnitInformation[VtdIndex].QiFreeHead));
-
-  BaseDesc[mVtdUnitInformation[VtdIndex].QiFreeHead].Low = Desc->Low;
-  BaseDesc[mVtdUnitInformation[VtdIndex].QiFreeHead].High = Desc->High;
-  FlushPageTableMemory(VtdIndex, (UINTN) &BaseDesc[mVtdUnitInformation[VtdIndex].QiFreeHead], sizeof(QI_DESC));
+  VtdUnitBaseAddress = mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress;
+  IqaReg.Uint64 = MmioRead64 (VtdUnitBaseAddress + R_IQA_REG);
+  if (IqaReg.Bits.IQA == 0) {
+    return EFI_NOT_READY;
+  }
+  IqtReg.Uint64 = MmioRead64 (VtdUnitBaseAddress + R_IQT_REG);
 
-  mVtdUnitInformation[VtdIndex].QiFreeHead = (mVtdUnitInformation[VtdIndex].QiFreeHead + 1) % QiDescLength;
+  if (IqaReg.Bits.DW == 0) {
+    //
+    // 128-bit descriptor
+    //
+    QueueSize = (UINTN) (1 << (IqaReg.Bits.QS + 8));
+    Qi128Desc = (QI_DESC *) (UINTN) (IqaReg.Bits.IQA << VTD_PAGE_SHIFT);
+    QueueTail = (UINTN) IqtReg.Bits128Desc.QT;
+    Qi128Desc += QueueTail;
+    Qi128Desc->Low = Desc->Uint64[0];
+    Qi128Desc->High = Desc->Uint64[1];
+    FlushPageTableMemory (VtdIndex, (UINTN) Qi128Desc, sizeof(QI_DESC));
+    QueueTail = (QueueTail + 1) % QueueSize;
+
+    DEBUG ((DEBUG_VERBOSE, "[0x%x] Submit QI Descriptor 0x%x [0x%016lx, 0x%016lx]\n",
+            VtdUnitBaseAddress,
+            QueueTail,
+            Desc->Uint64[0],
+            Desc->Uint64[1]));
+
+    IqtReg.Bits128Desc.QT = QueueTail;
+  } else {
+    //
+    // 256-bit descriptor
+    //
+    QueueSize = (UINTN) (1 << (IqaReg.Bits.QS + 7));
+    Qi256Desc = (QI_256_DESC *) (UINTN) (IqaReg.Bits.IQA << VTD_PAGE_SHIFT);
+    QueueTail = (UINTN) IqtReg.Bits256Desc.QT;
+    Qi256Desc += QueueTail;
+    Qi256Desc->Uint64[0] = Desc->Uint64[0];
+    Qi256Desc->Uint64[1] = Desc->Uint64[1];
+    Qi256Desc->Uint64[2] = Desc->Uint64[2];
+    Qi256Desc->Uint64[3] = Desc->Uint64[3];
+    FlushPageTableMemory (VtdIndex, (UINTN) Qi256Desc, sizeof(QI_256_DESC));
+    QueueTail = (QueueTail + 1) % QueueSize;
+
+    DEBUG ((DEBUG_VERBOSE, "[0x%x] Submit QI Descriptor 0x%x [0x%016lx, 0x%016lx, 0x%016lx, 0x%016lx]\n",
+            VtdUnitBaseAddress,
+            QueueTail,
+            Desc->Uint64[0],
+            Desc->Uint64[1],
+            Desc->Uint64[2],
+            Desc->Uint64[3]));
+
+    IqtReg.Bits256Desc.QT = QueueTail;
+  }
 
   //
   // Update the HW tail register indicating the presence of new descriptors.
   //
-  Reg64Iqt = mVtdUnitInformation[VtdIndex].QiFreeHead << DMAR_IQ_SHIFT;
-  MmioWrite64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_IQT_REG, Reg64Iqt);
+  MmioWrite64 (VtdUnitBaseAddress + R_IQT_REG, IqtReg.Uint64);
 
   Status = EFI_SUCCESS;
   do {
@@ -260,8 +314,13 @@ SubmitQueuedInvalidationDescriptor (
       break;
     }
 
-    Reg64Iqh = MmioRead64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_IQH_REG);
-  } while (Reg64Iqt != Reg64Iqh);
+    IqhReg.Uint64 = MmioRead64 (VtdUnitBaseAddress + R_IQH_REG);
+    if (IqaReg.Bits.DW == 0) {
+      QueueHead = (UINTN) IqhReg.Bits128Desc.QH;
+    } else {
+      QueueHead = (UINTN) IqhReg.Bits256Desc.QH;
+    }
+  } while (QueueTail != QueueHead);
 
   return Status;
 }
@@ -276,8 +335,8 @@ InvalidateContextCache (
   IN UINTN  VtdIndex
   )
 {
-  UINT64     Reg64;
-  QI_DESC    QiDesc;
+  UINT64         Reg64;
+  QI_256_DESC    QiDesc;
 
   if (mVtdUnitInformation[VtdIndex].EnableQueuedInvalidation == 0) {
     //
@@ -300,8 +359,10 @@ InvalidateContextCache (
     //
     // Queued Invalidation
     //
-    QiDesc.Low = QI_CC_FM(0) | QI_CC_SID(0) | QI_CC_DID(0) | QI_CC_GRAN(1) | QI_CC_TYPE;
-    QiDesc.High = 0;
+    QiDesc.Uint64[0] = QI_CC_FM(0) | QI_CC_SID(0) | QI_CC_DID(0) | QI_CC_GRAN(1) | QI_CC_TYPE;
+    QiDesc.Uint64[1] = 0;
+    QiDesc.Uint64[2] = 0;
+    QiDesc.Uint64[3] = 0;
 
     return SubmitQueuedInvalidationDescriptor(VtdIndex, &QiDesc);
   }
@@ -318,8 +379,8 @@ InvalidateIOTLB (
   IN UINTN  VtdIndex
   )
 {
-  UINT64     Reg64;
-  QI_DESC    QiDesc;
+  UINT64         Reg64;
+  QI_256_DESC    QiDesc;
 
   if (mVtdUnitInformation[VtdIndex].EnableQueuedInvalidation == 0) {
     //
@@ -342,8 +403,10 @@ InvalidateIOTLB (
     //
     // Queued Invalidation
     //
-    QiDesc.Low = QI_IOTLB_DID(0) | QI_IOTLB_DR(CAP_READ_DRAIN(mVtdUnitInformation[VtdIndex].CapReg.Uint64)) | QI_IOTLB_DW(CAP_WRITE_DRAIN(mVtdUnitInformation[VtdIndex].CapReg.Uint64)) | QI_IOTLB_GRAN(1) | QI_IOTLB_TYPE;
-    QiDesc.High = QI_IOTLB_ADDR(0) | QI_IOTLB_IH(0) | QI_IOTLB_AM(0);
+    QiDesc.Uint64[0] = QI_IOTLB_DID(0) | QI_IOTLB_DR(CAP_READ_DRAIN(mVtdUnitInformation[VtdIndex].CapReg.Uint64)) | QI_IOTLB_DW(CAP_WRITE_DRAIN(mVtdUnitInformation[VtdIndex].CapReg.Uint64)) | QI_IOTLB_GRAN(1) | QI_IOTLB_TYPE;
+    QiDesc.Uint64[1] = QI_IOTLB_ADDR(0) | QI_IOTLB_IH(0) | QI_IOTLB_AM(0);
+    QiDesc.Uint64[2] = 0;
+    QiDesc.Uint64[3] = 0;
 
     return SubmitQueuedInvalidationDescriptor(VtdIndex, &QiDesc);
   }
@@ -611,11 +674,6 @@ EnableDmar (
     DEBUG((DEBUG_INFO, "EnableDmar: waiting for RTPS bit to be set... \n"));
     SetGlobalCommandRegisterBits (VtdUnitBaseAddress, B_GMCD_REG_SRTP);
 
-    //
-    // Init DMAr Fault Event and Data registers
-    //
-    MmioRead32 (mVtdUnitInformation[Index].VtdUnitBaseAddress + R_FEDATA_REG);
-
     //
     // Write Buffer Flush before invalidation
     //
diff --git a/Silicon/Intel/IntelSiliconPkg/Include/IndustryStandard/Vtd.h b/Silicon/Intel/IntelSiliconPkg/Include/IndustryStandard/Vtd.h
index 32fbdd02e..3e1b8c3c5 100644
--- a/Silicon/Intel/IntelSiliconPkg/Include/IndustryStandard/Vtd.h
+++ b/Silicon/Intel/IntelSiliconPkg/Include/IndustryStandard/Vtd.h
@@ -259,6 +259,8 @@ typedef union {
 
 #define R_IQA_REG        0x90
 
+#define R_IQERCD_REG     0xB0
+
 #define VTD_PAGE_SHIFT   (12)
 #define VTD_PAGE_SIZE    (1UL << VTD_PAGE_SHIFT)
 #define VTD_PAGE_MASK    (((UINT64)-1) << VTD_PAGE_SHIFT)
@@ -289,13 +291,20 @@ typedef union {
 #define QI_IWD_STATUS_WRITE (((UINT64)1) << 5)
 
 //
-// This is the queued invalidate descriptor.
+// queued invalidation 128-bit descriptor
 //
 typedef struct {
-  UINT64 Low;
-  UINT64 High;
+  UINT64          Low;
+  UINT64          High;
 } QI_DESC;
 
+//
+// queued invalidation 256-bit descriptor
+//
+typedef struct {
+  UINT64          Uint64[4];
+} QI_256_DESC;
+
 typedef union {
   struct {
     UINT8         Minor:4;
@@ -411,6 +420,56 @@ typedef union {
   UINT64     Uint64[2];
 } VTD_FRCD_REG;
 
+typedef union {
+  struct {
+    UINT32   IQEI:4;       // Invalidation Queue Error Info
+    UINT32   Rsvd_4:28;
+    UINT32   ITESID:16;    // Invalidation Time-out Error Source Identifier
+    UINT32   ICESID:16;    // Invalidation Completion Error Source Identifier
+  } Bits;
+  UINT64     Uint64;
+} VTD_IQERCD_REG;
+
+typedef union {
+  struct {
+    UINT64   Rsvd_0:4;
+    UINT64   QH:15;         // Queue Head
+    UINT64   Rsvd_19:45;
+  } Bits128Desc;
+  struct {
+    UINT64   Rsvd_0:4;
+    UINT64   Rsvd_4:1;
+    UINT64   QH:14;         // Queue Head
+    UINT64   Rsvd_19:45;
+  } Bits256Desc;
+  UINT64     Uint64;
+} VTD_IQH_REG;
+
+typedef union {
+  struct {
+    UINT64   Rsvd_0:4;
+    UINT64   QT:15;         // Queue Tail
+    UINT64   Rsvd_19:45;
+  } Bits128Desc;
+  struct {
+    UINT64   Rsvd_0:4;
+    UINT64   Rsvd_4:1;
+    UINT64   QT:14;         // Queue Tail
+    UINT64   Rsvd_19:45;
+  } Bits256Desc;
+  UINT64     Uint64;
+} VTD_IQT_REG;
+
+typedef union {
+  struct {
+    UINT64   QS:3;         // Queue Size
+    UINT64   Rsvd_3:8;
+    UINT64   DW:1;         // Descriptor Width
+    UINT64   IQA:52;       // Invalidation Queue Base Address
+  } Bits;
+  UINT64     Uint64;
+} VTD_IQA_REG;
+
 typedef union {
   struct {
     UINT8    Function:3;
-- 
2.26.2.windows.1


^ permalink raw reply related	[flat|nested] 2+ messages in thread

* [PATCH] IntelSiliconPkg/VTd: Use 256-bit invaildation queue descriptor
@ 2022-11-30  5:15 Sheng Wei
  0 siblings, 0 replies; 2+ messages in thread
From: Sheng Wei @ 2022-11-30  5:15 UTC (permalink / raw)
  To: devel; +Cc: Ray Ni, Rangasai V Chaganty, Jenny Huang, Robert Kowalewski

256-bit invaildation queue descriptor could be used for both
abort DMA mode and legacy mode.

Signed-off-by: Sheng Wei <w.sheng@intel.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Rangasai V Chaganty <rangasai.v.chaganty@intel.com>
Cc: Jenny Huang <jenny.huang@intel.com>
Cc: Robert Kowalewski <robert.kowalewski@intel.com>
---
 .../VTd/IntelVTdDmarPei/IntelVTdDmar.c        | 188 ++++++++-----
 .../VTd/IntelVTdDmarPei/IntelVTdDmarPei.h     |   5 +-
 .../Feature/VTd/IntelVTdDxe/DmaProtection.c   |   3 +
 .../Feature/VTd/IntelVTdDxe/DmaProtection.h   |   5 +-
 .../Feature/VTd/IntelVTdDxe/VtdReg.c          | 248 +++++++++++-------
 .../Include/IndustryStandard/Vtd.h            |  65 ++++-
 6 files changed, 355 insertions(+), 159 deletions(-)

diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDmarPei/IntelVTdDmar.c b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDmarPei/IntelVTdDmar.c
index af85a3d8e..0c9805550 100644
--- a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDmarPei/IntelVTdDmar.c
+++ b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDmarPei/IntelVTdDmar.c
@@ -79,10 +79,11 @@ PerpareCacheInvalidationInterface (
   IN VTD_UNIT_INFO *VTdUnitInfo
   )
 {
-  UINT16         QueueSize;
-  UINT64         Reg64;
+  UINT8          DescriptorWidth;
+  UINTN          QueueSize;
   UINT32         Reg32;
   VTD_ECAP_REG   ECapReg;
+  VTD_IQA_REG    IqaReg;
   UINTN          VtdUnitBaseAddress;
 
   VtdUnitBaseAddress = VTdUnitInfo->VtdUnitBaseAddress;
@@ -121,20 +122,34 @@ PerpareCacheInvalidationInterface (
   //
   // Setup the IQ address, size and descriptor width through the Invalidation Queue Address Register
   //
-  if (VTdUnitInfo->QiDesc == NULL) {
+  if (VTdUnitInfo->QiDescBuffer == NULL) {
+    //
+    // It uses 256-bit descriptor
+    // Queue size is 128.
+    //
+    DescriptorWidth = 1;
     QueueSize = 0;
-    VTdUnitInfo->QiDescLength = 1 << (QueueSize + 8);
-    VTdUnitInfo->QiDesc = (QI_DESC *) AllocatePages (EFI_SIZE_TO_PAGES (sizeof (QI_DESC) * VTdUnitInfo->QiDescLength));
-    if (VTdUnitInfo->QiDesc == NULL) {
+
+    VTdUnitInfo->QiDescBufferSize = (sizeof (QI_256_DESC) * ((UINTN) 1 << (QueueSize + 7)));
+    VTdUnitInfo->QiDescBuffer = AllocatePages (EFI_SIZE_TO_PAGES (VTdUnitInfo->QiDescBufferSize));
+    if (VTdUnitInfo->QiDescBuffer == NULL) {
       DEBUG ((DEBUG_ERROR,"Could not Alloc Invalidation Queue Buffer.\n"));
       return EFI_OUT_OF_RESOURCES;
     }
   }
 
-  DEBUG ((DEBUG_INFO, "Invalidation Queue Length : %d\n", VTdUnitInfo->QiDescLength));
-  Reg64 = (UINT64) (UINTN) VTdUnitInfo->QiDesc;
-  Reg64 |= QueueSize;
-  MmioWrite64 (VtdUnitBaseAddress + R_IQA_REG, Reg64);
+  DEBUG ((DEBUG_INFO, "Invalidation Queue Buffer Size : %d\n", VTdUnitInfo->QiDescBufferSize));
+  //
+  // 4KB Aligned address
+  //
+  IqaReg.Uint64 = (UINT64) (UINTN) VTdUnitInfo->QiDescBuffer;
+  IqaReg.Bits.DW = DescriptorWidth;
+  IqaReg.Bits.QS = QueueSize;
+  MmioWrite64 (VtdUnitBaseAddress + R_IQA_REG, IqaReg.Uint64);
+  IqaReg.Uint64 = MmioRead64 (VtdUnitBaseAddress + R_IQA_REG);
+  DEBUG ((DEBUG_INFO, "IQA_REG [0x%lx]\n", IqaReg.Uint64));
+
+  DEBUG ((DEBUG_INFO, "IQH_REG [0x%lx]\n", MmioRead64 (VtdUnitBaseAddress + R_IQH_REG)));
 
   //
   // Enable the queued invalidation interface through the Global Command Register.
@@ -148,8 +163,6 @@ PerpareCacheInvalidationInterface (
     Reg32 = MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG);
   } while ((Reg32 & B_GSTS_REG_QIES) == 0);
 
-  VTdUnitInfo->QiFreeHead = 0;
-
   return EFI_SUCCESS;
 }
 
@@ -174,10 +187,10 @@ DisableQueuedInvalidationInterface (
       Reg32 = MmioRead32 (VTdUnitInfo->VtdUnitBaseAddress + R_GSTS_REG);
     } while ((Reg32 & B_GSTS_REG_QIES) != 0);
 
-    if (VTdUnitInfo->QiDesc != NULL) {
-      FreePages(VTdUnitInfo->QiDesc, EFI_SIZE_TO_PAGES (sizeof (QI_DESC) * VTdUnitInfo->QiDescLength));
-      VTdUnitInfo->QiDesc = NULL;
-      VTdUnitInfo->QiDescLength = 0;
+    if (VTdUnitInfo->QiDescBuffer != NULL) {
+      FreePages(VTdUnitInfo->QiDescBuffer, EFI_SIZE_TO_PAGES (VTdUnitInfo->QiDescBufferSize));
+      VTdUnitInfo->QiDescBuffer = NULL;
+      VTdUnitInfo->QiDescBufferSize = 0;
     }
 
     VTdUnitInfo->EnableQueuedInvalidation = 0;
@@ -197,12 +210,15 @@ QueuedInvalidationCheckFault (
   IN VTD_UNIT_INFO *VTdUnitInfo
   )
 {
-  UINT32     FaultReg;
+  UINT32            FaultReg;
+  VTD_IQERCD_REG    IqercdReg;
 
   FaultReg = MmioRead32 (VTdUnitInfo->VtdUnitBaseAddress + R_FSTS_REG);
   if (FaultReg & (B_FSTS_REG_IQE | B_FSTS_REG_ITE | B_FSTS_REG_ICE)) {
-    DEBUG((DEBUG_ERROR, "Detect Queue Invalidation Error [0x%08x]\n", FaultReg));
-    FaultReg |= (B_FSTS_REG_IQE | B_FSTS_REG_ITE | B_FSTS_REG_ICE);
+    IqercdReg.Uint64 = MmioRead64 (VTdUnitInfo->VtdUnitBaseAddress + R_IQERCD_REG);
+
+    DEBUG((DEBUG_ERROR, "Detect Queue Invalidation Error [0x%08x] - IQERCD [0x%016lx]\n", FaultReg, IqercdReg.Uint64));
+
     MmioWrite32 (VTdUnitInfo->VtdUnitBaseAddress + R_FSTS_REG, FaultReg);
     return RETURN_DEVICE_ERROR;
   }
@@ -223,37 +239,83 @@ QueuedInvalidationCheckFault (
 **/
 EFI_STATUS
 SubmitQueuedInvalidationDescriptor (
-  IN VTD_UNIT_INFO *VTdUnitInfo,
-  IN QI_DESC       *Desc
+  IN VTD_UNIT_INFO     *VTdUnitInfo,
+  IN QI_256_DESC       *Desc
   )
 {
-  EFI_STATUS Status;
-  UINT16     QiDescLength;
-  QI_DESC    *BaseDesc;
-  UINT64     Reg64Iqt;
-  UINT64     Reg64Iqh;
+  EFI_STATUS     Status;
+  UINTN          VtdUnitBaseAddress;
+  UINTN          QueueSize;
+  UINTN          QueueTail;
+  UINTN          QueueHead;
+  QI_DESC        *Qi128Desc;
+  QI_256_DESC    *Qi256Desc;
+  VTD_IQA_REG    IqaReg;
+  VTD_IQT_REG    IqtReg;
+  VTD_IQH_REG    IqhReg;
 
   if (Desc == NULL) {
     return EFI_INVALID_PARAMETER;
   }
 
-  QiDescLength = VTdUnitInfo->QiDescLength;
-  BaseDesc = VTdUnitInfo->QiDesc;
-
-  DEBUG((DEBUG_INFO, "[0x%x] Submit QI Descriptor [0x%016lx, 0x%016lx]\n", VTdUnitInfo->VtdUnitBaseAddress, Desc->Low, Desc->High));
-
-  BaseDesc[VTdUnitInfo->QiFreeHead].Low = Desc->Low;
-  BaseDesc[VTdUnitInfo->QiFreeHead].High = Desc->High;
-  FlushPageTableMemory(VTdUnitInfo, (UINTN) &BaseDesc[VTdUnitInfo->QiFreeHead], sizeof(QI_DESC));
+  VtdUnitBaseAddress = VTdUnitInfo->VtdUnitBaseAddress;
+  IqaReg.Uint64 = MmioRead64 (VtdUnitBaseAddress + R_IQA_REG);
+  if (IqaReg.Bits.IQA == 0) {
+    DEBUG ((DEBUG_ERROR,"Invalidation Queue Buffer not ready [0x%lx]\n", IqaReg.Uint64));
+    return EFI_NOT_READY;
+  }
+  IqtReg.Uint64 = MmioRead64 (VtdUnitBaseAddress + R_IQT_REG);
 
-  DEBUG((DEBUG_INFO,"QI Free Head=0x%x\n", VTdUnitInfo->QiFreeHead));
-  VTdUnitInfo->QiFreeHead = (VTdUnitInfo->QiFreeHead + 1) % QiDescLength;
+  if (IqaReg.Bits.DW == 0) {
+    //
+    // 128-bit descriptor
+    //
+    QueueSize = (UINTN) (1 << (IqaReg.Bits.QS + 8));
+    Qi128Desc = (QI_DESC *) (UINTN) (IqaReg.Bits.IQA << VTD_PAGE_SHIFT);
+    QueueTail = (UINTN) IqtReg.Bits128Desc.QT;
+    Qi128Desc += QueueTail;
+    Qi128Desc->Low = Desc->Uint64[0];
+    Qi128Desc->High = Desc->Uint64[1];
+    FlushPageTableMemory (VTdUnitInfo, (UINTN) Qi128Desc, sizeof(QI_DESC));
+    QueueTail = (QueueTail + 1) % QueueSize;
+
+    DEBUG ((DEBUG_INFO, "[0x%x] Submit QI Descriptor 0x%x [0x%016lx, 0x%016lx]\n",
+            VtdUnitBaseAddress,
+            QueueTail,
+            Desc->Uint64[0],
+            Desc->Uint64[1]));
+
+    IqtReg.Bits128Desc.QT = QueueTail;
+  } else {
+    //
+    // 256-bit descriptor
+    //
+    QueueSize = (UINTN) (1 << (IqaReg.Bits.QS + 7));
+    Qi256Desc = (QI_256_DESC *) (UINTN) (IqaReg.Bits.IQA << VTD_PAGE_SHIFT);
+    QueueTail = (UINTN) IqtReg.Bits256Desc.QT;
+    Qi256Desc += QueueTail;
+    Qi256Desc->Uint64[0] = Desc->Uint64[0];
+    Qi256Desc->Uint64[1] = Desc->Uint64[1];
+    Qi256Desc->Uint64[2] = Desc->Uint64[2];
+    Qi256Desc->Uint64[3] = Desc->Uint64[3];
+    FlushPageTableMemory (VTdUnitInfo, (UINTN) Qi256Desc, sizeof(QI_256_DESC));
+    QueueTail = (QueueTail + 1) % QueueSize;
+
+    DEBUG ((DEBUG_INFO, "[0x%x] Submit QI Descriptor 0x%x [0x%016lx, 0x%016lx, 0x%016lx, 0x%016lx]\n",
+            VtdUnitBaseAddress,
+            QueueTail,
+            Desc->Uint64[0],
+            Desc->Uint64[1],
+            Desc->Uint64[2],
+            Desc->Uint64[3]));
+
+    IqtReg.Bits256Desc.QT = QueueTail;
+  }
 
   //
   // Update the HW tail register indicating the presence of new descriptors.
   //
-  Reg64Iqt = VTdUnitInfo->QiFreeHead << DMAR_IQ_SHIFT;
-  MmioWrite64 (VTdUnitInfo->VtdUnitBaseAddress + R_IQT_REG, Reg64Iqt);
+  MmioWrite64 (VtdUnitBaseAddress + R_IQT_REG, IqtReg.Uint64);
 
   Status = EFI_SUCCESS;
   do {
@@ -263,10 +325,15 @@ SubmitQueuedInvalidationDescriptor (
       break;
     }
 
-    Reg64Iqh = MmioRead64 (VTdUnitInfo->VtdUnitBaseAddress + R_IQH_REG);
-  } while (Reg64Iqt != Reg64Iqh);
+    IqhReg.Uint64 = MmioRead64 (VtdUnitBaseAddress + R_IQH_REG);
+    if (IqaReg.Bits.DW == 0) {
+      QueueHead = (UINTN) IqhReg.Bits128Desc.QH;
+    } else {
+      QueueHead = (UINTN) IqhReg.Bits256Desc.QH;
+    }
+  } while (QueueTail != QueueHead);
 
-  DEBUG((DEBUG_ERROR,"SubmitQueuedInvalidationDescriptor end\n"));
+  DEBUG((DEBUG_INFO,"SubmitQueuedInvalidationDescriptor end\n"));
   return Status;
 }
 
@@ -281,7 +348,7 @@ InvalidateContextCache (
   )
 {
   UINT64                        Reg64;
-  QI_DESC                       QiDesc;
+  QI_256_DESC                   QiDesc;
 
   if (VTdUnitInfo->EnableQueuedInvalidation == 0) {
     //
@@ -304,8 +371,10 @@ InvalidateContextCache (
     //
     // Queued Invalidation
     //
-    QiDesc.Low = QI_CC_FM(0) | QI_CC_SID(0) | QI_CC_DID(0) | QI_CC_GRAN(1) | QI_CC_TYPE;
-    QiDesc.High = 0;
+    QiDesc.Uint64[0] = QI_CC_FM(0) | QI_CC_SID(0) | QI_CC_DID(0) | QI_CC_GRAN(1) | QI_CC_TYPE;
+    QiDesc.Uint64[1] = 0;
+    QiDesc.Uint64[2] = 0;
+    QiDesc.Uint64[3] = 0;
 
     return SubmitQueuedInvalidationDescriptor(VTdUnitInfo, &QiDesc);
   }
@@ -326,7 +395,7 @@ InvalidateIOTLB (
   UINT64                        Reg64;
   VTD_ECAP_REG                  ECapReg;
   VTD_CAP_REG                   CapReg;
-  QI_DESC                       QiDesc;
+  QI_256_DESC                   QiDesc;
 
   if (VTdUnitInfo->EnableQueuedInvalidation == 0) {
     //
@@ -352,8 +421,10 @@ InvalidateIOTLB (
     // Queued Invalidation
     //
     CapReg.Uint64 = MmioRead64 (VTdUnitInfo->VtdUnitBaseAddress + R_CAP_REG);
-    QiDesc.Low = QI_IOTLB_DID(0) | QI_IOTLB_DR(CAP_READ_DRAIN(CapReg.Uint64)) | QI_IOTLB_DW(CAP_WRITE_DRAIN(CapReg.Uint64)) | QI_IOTLB_GRAN(1) | QI_IOTLB_TYPE;
-    QiDesc.High = QI_IOTLB_ADDR(0) | QI_IOTLB_IH(0) | QI_IOTLB_AM(0);
+    QiDesc.Uint64[0] = QI_IOTLB_DID(0) | QI_IOTLB_DR(CAP_READ_DRAIN(CapReg.Uint64)) | QI_IOTLB_DW(CAP_WRITE_DRAIN(CapReg.Uint64)) | QI_IOTLB_GRAN(1) | QI_IOTLB_TYPE;
+    QiDesc.Uint64[1] = QI_IOTLB_ADDR(0) | QI_IOTLB_IH(0) | QI_IOTLB_AM(0);
+    QiDesc.Uint64[2] = 0;
+    QiDesc.Uint64[3] = 0;
 
     return SubmitQueuedInvalidationDescriptor(VTdUnitInfo, &QiDesc);
   }
@@ -390,6 +461,7 @@ ClearGlobalCommandRegisterBits (
   do {
     Reg32 = MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG);
   } while ((Reg32 & BitMask) == BitMask);
+  DEBUG ((DEBUG_INFO, "GSTS_REG : 0x%08x \n", Reg32));
 }
 
 /**
@@ -421,6 +493,7 @@ SetGlobalCommandRegisterBits (
   do {
     Reg32 = MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG);
   } while ((Reg32 & BitMask) == 0);
+  DEBUG ((DEBUG_INFO, "GSTS_REG : 0x%08x \n", Reg32));
 }
 
 /**
@@ -451,11 +524,6 @@ EnableDmarPreMem (
   Reg32 = MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG);
   DEBUG ((DEBUG_INFO, "EnableDmarPreMem: R_GSTS_REG = 0x%x \n", Reg32));
 
-  //
-  // Init DMAr Fault Event and Data registers
-  //
-  Reg32 = MmioRead32 (VtdUnitBaseAddress + R_FEDATA_REG);
-
   //
   // Write Buffer Flush
   //
@@ -513,6 +581,9 @@ EnableDmar (
     //
     MmioWrite64 (VtdUnitBaseAddress + R_RTADDR_REG, (UINT64) (RootEntryTable | V_RTADDR_REG_TTM_ADM));
 
+    DEBUG ((DEBUG_INFO, "EnableDmar: waiting for RTPS bit to be set... \n"));
+    SetGlobalCommandRegisterBits (VtdUnitBaseAddress, B_GMCD_REG_SRTP);
+
     DEBUG((DEBUG_INFO, "Enable Abort DMA Mode...\n"));
     SetGlobalCommandRegisterBits (VtdUnitBaseAddress, B_GMCD_REG_TE);
 
@@ -520,16 +591,10 @@ EnableDmar (
     DEBUG ((DEBUG_INFO, "RootEntryTable 0x%x \n", RootEntryTable));
     MmioWrite64 (VtdUnitBaseAddress + R_RTADDR_REG, (UINT64) RootEntryTable);
 
+    DEBUG ((DEBUG_INFO, "EnableDmar: waiting for RTPS bit to be set... \n"));
+    SetGlobalCommandRegisterBits (VtdUnitBaseAddress, B_GMCD_REG_SRTP);
   }
 
-  DEBUG ((DEBUG_INFO, "EnableDmar: waiting for RTPS bit to be set... \n"));
-  SetGlobalCommandRegisterBits (VtdUnitBaseAddress, B_GMCD_REG_SRTP);
-
-  //
-  // Init DMAr Fault Event and Data registers
-  //
-  MmioRead32 (VtdUnitBaseAddress + R_FEDATA_REG);
-
   //
   // Write Buffer Flush before invalidation
   //
@@ -552,6 +617,9 @@ EnableDmar (
 
     DEBUG ((DEBUG_INFO, "RootEntryTable 0x%x \n", RootEntryTable));
     MmioWrite64 (VtdUnitBaseAddress + R_RTADDR_REG, (UINT64) RootEntryTable);
+
+    DEBUG ((DEBUG_INFO, "EnableDmar: waiting for RTPS bit to be set... \n"));
+    SetGlobalCommandRegisterBits (VtdUnitBaseAddress, B_GMCD_REG_SRTP);
   }
 
   //
diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDmarPei/IntelVTdDmarPei.h b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDmarPei/IntelVTdDmarPei.h
index 5ade9ec35..4d4b912f2 100644
--- a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDmarPei/IntelVTdDmarPei.h
+++ b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDmarPei/IntelVTdDmarPei.h
@@ -21,9 +21,8 @@ typedef struct {
   VTD_ECAP_REG                     ECapReg;
   BOOLEAN                          Is5LevelPaging;
   UINT8                            EnableQueuedInvalidation;
-  UINT16                           QiDescLength;
-  QI_DESC                          *QiDesc;
-  UINT16                           QiFreeHead;
+  VOID                             *QiDescBuffer;
+  UINTN                            QiDescBufferSize;
   UINTN                            FixedSecondLevelPagingEntry;
   UINTN                            RootEntryTable;
   UINTN                            ExtRootEntryTable;
diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/DmaProtection.c b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/DmaProtection.c
index 628565ee7..878c952b7 100644
--- a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/DmaProtection.c
+++ b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/DmaProtection.c
@@ -496,6 +496,9 @@ SetupVtd (
   if (EFI_ERROR (Status)) {
     return;
   }
+
+  DumpVtdIfError ();
+
   DEBUG ((DEBUG_INFO, "PrepareVtdConfig\n"));
   PrepareVtdConfig ();
 
diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/DmaProtection.h b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/DmaProtection.h
index 7dd29a243..e83ebff41 100644
--- a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/DmaProtection.h
+++ b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/DmaProtection.h
@@ -81,9 +81,8 @@ typedef struct {
   PCI_DEVICE_INFORMATION           PciDeviceInfo;
   BOOLEAN                          Is5LevelPaging;
   UINT8                            EnableQueuedInvalidation;
-  UINT16                           QiDescLength;
-  QI_DESC                          *QiDesc;
-  UINT16                           QiFreeHead;
+  VOID                             *QiDescBuffer;
+  UINTN                            QiDescBufferSize;
 } VTD_UNIT_INFORMATION;
 
 //
diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/VtdReg.c b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/VtdReg.c
index 8e834f4c4..be54cf99d 100644
--- a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/VtdReg.c
+++ b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/VtdReg.c
@@ -68,71 +68,89 @@ PerpareCacheInvalidationInterface (
   IN UINTN  VtdIndex
   )
 {
-  UINT16  QueueSize;
-  UINT64  Reg64;
-  UINT32  Reg32;
-
-  if (mVtdUnitInformation[VtdIndex].VerReg.Bits.Major <= 5) {
-    mVtdUnitInformation[VtdIndex].EnableQueuedInvalidation = 0;
+  UINT8                 DescriptorWidth;
+  UINTN                 QueueSize;
+  UINT32                Reg32;
+  VTD_IQA_REG           IqaReg;
+  VTD_UNIT_INFORMATION  *VTdUnitInfo;
+  UINTN                 VtdUnitBaseAddress;
+
+  VTdUnitInfo = &mVtdUnitInformation[VtdIndex];
+  VtdUnitBaseAddress = VTdUnitInfo->VtdUnitBaseAddress;
+
+  if (VTdUnitInfo->VerReg.Bits.Major <= 5) {
+    VTdUnitInfo->EnableQueuedInvalidation = 0;
     DEBUG ((DEBUG_INFO, "Use Register-based Invalidation Interface for engine [%d]\n", VtdIndex));
     return EFI_SUCCESS;
   }
 
-  if (mVtdUnitInformation[VtdIndex].ECapReg.Bits.QI == 0) {
+  if (VTdUnitInfo->ECapReg.Bits.QI == 0) {
     DEBUG ((DEBUG_ERROR, "Hardware does not support queued invalidations interface for engine [%d]\n", VtdIndex));
     return EFI_UNSUPPORTED;
   }
 
-  mVtdUnitInformation[VtdIndex].EnableQueuedInvalidation = 1;
+  VTdUnitInfo->EnableQueuedInvalidation = 1;
   DEBUG ((DEBUG_INFO, "Use Queued Invalidation Interface for engine [%d]\n", VtdIndex));
 
-  Reg32 = MmioRead32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_GSTS_REG);
+  Reg32 = MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG);
   if ((Reg32 & B_GSTS_REG_QIES) != 0) {
     DEBUG ((DEBUG_ERROR,"Queued Invalidation Interface was enabled.\n"));
     Reg32 &= (~B_GSTS_REG_QIES);
-    MmioWrite32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_GCMD_REG, Reg32);
+    MmioWrite32 (VtdUnitBaseAddress + R_GCMD_REG, Reg32);
     do {
-      Reg32 = MmioRead32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_GSTS_REG);
+      Reg32 = MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG);
     } while ((Reg32 & B_GSTS_REG_QIES) != 0);
   }
 
   //
   // Initialize the Invalidation Queue Tail Register to zero.
   //
-  MmioWrite64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_IQT_REG, 0);
+  MmioWrite64 (VtdUnitBaseAddress + R_IQT_REG, 0);
 
   //
   // Setup the IQ address, size and descriptor width through the Invalidation Queue Address Register
   //
-  QueueSize = 0;
-  mVtdUnitInformation[VtdIndex].QiDescLength = 1 << (QueueSize + 8);
-  mVtdUnitInformation[VtdIndex].QiDesc = (QI_DESC *) AllocatePages (EFI_SIZE_TO_PAGES(sizeof(QI_DESC) * mVtdUnitInformation[VtdIndex].QiDescLength));
-
-  if (mVtdUnitInformation[VtdIndex].QiDesc == NULL) {
-    mVtdUnitInformation[VtdIndex].QiDescLength = 0;
-    DEBUG ((DEBUG_ERROR,"Could not Alloc Invalidation Queue Buffer.\n"));
-    return EFI_OUT_OF_RESOURCES;
+  if (VTdUnitInfo->QiDescBuffer == NULL) {
+    //
+    // It uses 256-bit descriptor
+    // Queue size is 128.
+    //
+    DescriptorWidth = 1;
+    QueueSize = 0;
+
+    VTdUnitInfo->QiDescBufferSize = (sizeof (QI_256_DESC) * ((UINTN) 1 << (QueueSize + 7)));
+    VTdUnitInfo->QiDescBuffer = AllocatePages (EFI_SIZE_TO_PAGES (VTdUnitInfo->QiDescBufferSize));
+    if (VTdUnitInfo->QiDescBuffer == NULL) {
+      DEBUG ((DEBUG_ERROR,"Could not Alloc Invalidation Queue Buffer.\n"));
+      return EFI_OUT_OF_RESOURCES;
+    }
   }
 
-  DEBUG ((DEBUG_INFO, "Invalidation Queue Length : %d\n", mVtdUnitInformation[VtdIndex].QiDescLength));
-  Reg64 = (UINT64)(UINTN)mVtdUnitInformation[VtdIndex].QiDesc;
-  Reg64 |= QueueSize;
-  MmioWrite64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_IQA_REG, Reg64);
+  DEBUG ((DEBUG_INFO, "Invalidation Queue Buffer Size : %d\n", VTdUnitInfo->QiDescBufferSize));
+  //
+  // 4KB Aligned address
+  //
+  IqaReg.Uint64 = (UINT64) (UINTN) VTdUnitInfo->QiDescBuffer;
+  IqaReg.Bits.DW = DescriptorWidth;
+  IqaReg.Bits.QS = QueueSize;
+  MmioWrite64 (VtdUnitBaseAddress + R_IQA_REG, IqaReg.Uint64);
+  IqaReg.Uint64 = MmioRead64 (VtdUnitBaseAddress + R_IQA_REG);
+  DEBUG ((DEBUG_INFO, "IQA_REG [0x%lx]\n", IqaReg.Uint64));
+
+  DEBUG ((DEBUG_INFO, "IQH_REG [0x%lx]\n", MmioRead64 (VtdUnitBaseAddress + R_IQH_REG)));
 
   //
   // Enable the queued invalidation interface through the Global Command Register.
   // When enabled, hardware sets the QIES field in the Global Status Register.
   //
-  Reg32 = MmioRead32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_GSTS_REG);
+  Reg32 = MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG);
   Reg32 |= B_GMCD_REG_QIE;
-  MmioWrite32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_GCMD_REG, Reg32);
+  MmioWrite32 (VtdUnitBaseAddress + R_GCMD_REG, Reg32);
   DEBUG ((DEBUG_INFO, "Enable Queued Invalidation Interface. GCMD_REG = 0x%x\n", Reg32));
   do {
-    Reg32 = MmioRead32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_GSTS_REG);
+    Reg32 = MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG);
   } while ((Reg32 & B_GSTS_REG_QIES) == 0);
 
-  mVtdUnitInformation[VtdIndex].QiFreeHead = 0;
-
   return EFI_SUCCESS;
 }
 
@@ -146,21 +164,24 @@ DisableQueuedInvalidationInterface (
   IN UINTN  VtdIndex
   )
 {
-  UINT32  Reg32;
+  UINT32                Reg32;
+  VTD_UNIT_INFORMATION  *VTdUnitInfo;
 
-  if (mVtdUnitInformation[VtdIndex].EnableQueuedInvalidation != 0) {
-    Reg32 = MmioRead32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_GSTS_REG);
+  VTdUnitInfo = &mVtdUnitInformation[VtdIndex];
+
+  if (VTdUnitInfo->EnableQueuedInvalidation != 0) {
+    Reg32 = MmioRead32 (VTdUnitInfo->VtdUnitBaseAddress + R_GSTS_REG);
     Reg32 &= (~B_GMCD_REG_QIE);
-    MmioWrite32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_GCMD_REG, Reg32);
+    MmioWrite32 (VTdUnitInfo->VtdUnitBaseAddress + R_GCMD_REG, Reg32);
     DEBUG ((DEBUG_INFO, "Disable Queued Invalidation Interface. GCMD_REG = 0x%x\n", Reg32));
     do {
-      Reg32 = MmioRead32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_GSTS_REG);
+      Reg32 = MmioRead32 (VTdUnitInfo->VtdUnitBaseAddress + R_GSTS_REG);
     } while ((Reg32 & B_GSTS_REG_QIES) != 0);
 
-    if (mVtdUnitInformation[VtdIndex].QiDesc != NULL) {
-      FreePages(mVtdUnitInformation[VtdIndex].QiDesc, EFI_SIZE_TO_PAGES(sizeof(QI_DESC) * mVtdUnitInformation[VtdIndex].QiDescLength));
-      mVtdUnitInformation[VtdIndex].QiDesc = NULL;
-      mVtdUnitInformation[VtdIndex].QiDescLength = 0;
+    if (VTdUnitInfo->QiDescBuffer != NULL) {
+      FreePages(VTdUnitInfo->QiDescBuffer, EFI_SIZE_TO_PAGES (VTdUnitInfo->QiDescBufferSize));
+      VTdUnitInfo->QiDescBuffer = NULL;
+      VTdUnitInfo->QiDescBufferSize = 0;
     }
 
     mVtdUnitInformation[VtdIndex].EnableQueuedInvalidation = 0;
@@ -180,27 +201,16 @@ QueuedInvalidationCheckFault (
   IN UINTN  VtdIndex
   )
 {
-  UINT32     FaultReg;
+  UINT32            FaultReg;
+  VTD_IQERCD_REG    IqercdReg;
 
   FaultReg = MmioRead32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_FSTS_REG);
 
-  if (FaultReg & B_FSTS_REG_IQE) {
-    DEBUG((DEBUG_ERROR, "Detect Invalidation Queue Error [0x%08x]\n", FaultReg));
-    FaultReg |= B_FSTS_REG_IQE;
-    MmioWrite32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_FSTS_REG, FaultReg);
-    return RETURN_DEVICE_ERROR;
-  }
+  if (FaultReg & (B_FSTS_REG_IQE | B_FSTS_REG_ITE | B_FSTS_REG_ICE)) {
+    IqercdReg.Uint64 = MmioRead64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_IQERCD_REG);
 
-  if (FaultReg & B_FSTS_REG_ITE) {
-    DEBUG((DEBUG_ERROR, "Detect Invalidation Time-out Error [0x%08x]\n", FaultReg));
-    FaultReg |= B_FSTS_REG_ITE;
-    MmioWrite32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_FSTS_REG, FaultReg);
-    return RETURN_DEVICE_ERROR;
-  }
+    DEBUG((DEBUG_ERROR, "Detect Queue Invalidation Error [0x%08x] - IQERCD [0x%016lx]\n", FaultReg, IqercdReg.Uint64));
 
-  if (FaultReg & B_FSTS_REG_ICE) {
-    DEBUG((DEBUG_ERROR, "Detect Invalidation Completion Error [0x%08x]\n", FaultReg));
-    FaultReg |= B_FSTS_REG_ICE;
     MmioWrite32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_FSTS_REG, FaultReg);
     return RETURN_DEVICE_ERROR;
   }
@@ -221,36 +231,83 @@ QueuedInvalidationCheckFault (
 **/
 EFI_STATUS
 SubmitQueuedInvalidationDescriptor (
-  IN UINTN    VtdIndex,
-  IN QI_DESC  *Desc
+  IN UINTN        VtdIndex,
+  IN QI_256_DESC  *Desc
   )
 {
-  EFI_STATUS Status;
-  UINT16     QiDescLength;
-  QI_DESC    *BaseDesc;
-  UINT64     Reg64Iqt;
-  UINT64     Reg64Iqh;
+  EFI_STATUS     Status;
+  UINTN          VtdUnitBaseAddress;
+  UINTN          QueueSize;
+  UINTN          QueueTail;
+  UINTN          QueueHead;
+  QI_DESC        *Qi128Desc;
+  QI_256_DESC    *Qi256Desc;
+  VTD_IQA_REG    IqaReg;
+  VTD_IQT_REG    IqtReg;
+  VTD_IQH_REG    IqhReg;
 
   if (Desc == NULL) {
     return EFI_INVALID_PARAMETER;
   }
 
-  QiDescLength = mVtdUnitInformation[VtdIndex].QiDescLength;
-  BaseDesc = mVtdUnitInformation[VtdIndex].QiDesc;
-
-  DEBUG((DEBUG_VERBOSE, "[%d] Submit QI Descriptor [0x%08x, 0x%08x] Free Head (%d)\n", VtdIndex, Desc->Low, Desc->High, mVtdUnitInformation[VtdIndex].QiFreeHead));
-
-  BaseDesc[mVtdUnitInformation[VtdIndex].QiFreeHead].Low = Desc->Low;
-  BaseDesc[mVtdUnitInformation[VtdIndex].QiFreeHead].High = Desc->High;
-  FlushPageTableMemory(VtdIndex, (UINTN) &BaseDesc[mVtdUnitInformation[VtdIndex].QiFreeHead], sizeof(QI_DESC));
+  VtdUnitBaseAddress = mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress;
+  IqaReg.Uint64 = MmioRead64 (VtdUnitBaseAddress + R_IQA_REG);
+  if (IqaReg.Bits.IQA == 0) {
+    DEBUG ((DEBUG_ERROR,"Invalidation Queue Buffer not ready [0x%lx]\n", IqaReg.Uint64));
+    return EFI_NOT_READY;
+  }
+  IqtReg.Uint64 = MmioRead64 (VtdUnitBaseAddress + R_IQT_REG);
 
-  mVtdUnitInformation[VtdIndex].QiFreeHead = (mVtdUnitInformation[VtdIndex].QiFreeHead + 1) % QiDescLength;
+  if (IqaReg.Bits.DW == 0) {
+    //
+    // 128-bit descriptor
+    //
+    QueueSize = (UINTN) (1 << (IqaReg.Bits.QS + 8));
+    Qi128Desc = (QI_DESC *) (UINTN) (IqaReg.Bits.IQA << VTD_PAGE_SHIFT);
+    QueueTail = (UINTN) IqtReg.Bits128Desc.QT;
+    Qi128Desc += QueueTail;
+    Qi128Desc->Low = Desc->Uint64[0];
+    Qi128Desc->High = Desc->Uint64[1];
+    FlushPageTableMemory (VtdIndex, (UINTN) Qi128Desc, sizeof(QI_DESC));
+    QueueTail = (QueueTail + 1) % QueueSize;
+
+    DEBUG ((DEBUG_VERBOSE, "[0x%x] Submit QI Descriptor 0x%x [0x%016lx, 0x%016lx]\n",
+            VtdUnitBaseAddress,
+            QueueTail,
+            Desc->Uint64[0],
+            Desc->Uint64[1]));
+
+    IqtReg.Bits128Desc.QT = QueueTail;
+  } else {
+    //
+    // 256-bit descriptor
+    //
+    QueueSize = (UINTN) (1 << (IqaReg.Bits.QS + 7));
+    Qi256Desc = (QI_256_DESC *) (UINTN) (IqaReg.Bits.IQA << VTD_PAGE_SHIFT);
+    QueueTail = (UINTN) IqtReg.Bits256Desc.QT;
+    Qi256Desc += QueueTail;
+    Qi256Desc->Uint64[0] = Desc->Uint64[0];
+    Qi256Desc->Uint64[1] = Desc->Uint64[1];
+    Qi256Desc->Uint64[2] = Desc->Uint64[2];
+    Qi256Desc->Uint64[3] = Desc->Uint64[3];
+    FlushPageTableMemory (VtdIndex, (UINTN) Qi256Desc, sizeof(QI_256_DESC));
+    QueueTail = (QueueTail + 1) % QueueSize;
+
+    DEBUG ((DEBUG_VERBOSE, "[0x%x] Submit QI Descriptor 0x%x [0x%016lx, 0x%016lx, 0x%016lx, 0x%016lx]\n",
+            VtdUnitBaseAddress,
+            QueueTail,
+            Desc->Uint64[0],
+            Desc->Uint64[1],
+            Desc->Uint64[2],
+            Desc->Uint64[3]));
+
+    IqtReg.Bits256Desc.QT = QueueTail;
+  }
 
   //
   // Update the HW tail register indicating the presence of new descriptors.
   //
-  Reg64Iqt = mVtdUnitInformation[VtdIndex].QiFreeHead << DMAR_IQ_SHIFT;
-  MmioWrite64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_IQT_REG, Reg64Iqt);
+  MmioWrite64 (VtdUnitBaseAddress + R_IQT_REG, IqtReg.Uint64);
 
   Status = EFI_SUCCESS;
   do {
@@ -260,8 +317,13 @@ SubmitQueuedInvalidationDescriptor (
       break;
     }
 
-    Reg64Iqh = MmioRead64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_IQH_REG);
-  } while (Reg64Iqt != Reg64Iqh);
+    IqhReg.Uint64 = MmioRead64 (VtdUnitBaseAddress + R_IQH_REG);
+    if (IqaReg.Bits.DW == 0) {
+      QueueHead = (UINTN) IqhReg.Bits128Desc.QH;
+    } else {
+      QueueHead = (UINTN) IqhReg.Bits256Desc.QH;
+    }
+  } while (QueueTail != QueueHead);
 
   return Status;
 }
@@ -276,8 +338,8 @@ InvalidateContextCache (
   IN UINTN  VtdIndex
   )
 {
-  UINT64     Reg64;
-  QI_DESC    QiDesc;
+  UINT64         Reg64;
+  QI_256_DESC    QiDesc;
 
   if (mVtdUnitInformation[VtdIndex].EnableQueuedInvalidation == 0) {
     //
@@ -300,8 +362,10 @@ InvalidateContextCache (
     //
     // Queued Invalidation
     //
-    QiDesc.Low = QI_CC_FM(0) | QI_CC_SID(0) | QI_CC_DID(0) | QI_CC_GRAN(1) | QI_CC_TYPE;
-    QiDesc.High = 0;
+    QiDesc.Uint64[0] = QI_CC_FM(0) | QI_CC_SID(0) | QI_CC_DID(0) | QI_CC_GRAN(1) | QI_CC_TYPE;
+    QiDesc.Uint64[1] = 0;
+    QiDesc.Uint64[2] = 0;
+    QiDesc.Uint64[3] = 0;
 
     return SubmitQueuedInvalidationDescriptor(VtdIndex, &QiDesc);
   }
@@ -318,8 +382,8 @@ InvalidateIOTLB (
   IN UINTN  VtdIndex
   )
 {
-  UINT64     Reg64;
-  QI_DESC    QiDesc;
+  UINT64         Reg64;
+  QI_256_DESC    QiDesc;
 
   if (mVtdUnitInformation[VtdIndex].EnableQueuedInvalidation == 0) {
     //
@@ -342,8 +406,10 @@ InvalidateIOTLB (
     //
     // Queued Invalidation
     //
-    QiDesc.Low = QI_IOTLB_DID(0) | QI_IOTLB_DR(CAP_READ_DRAIN(mVtdUnitInformation[VtdIndex].CapReg.Uint64)) | QI_IOTLB_DW(CAP_WRITE_DRAIN(mVtdUnitInformation[VtdIndex].CapReg.Uint64)) | QI_IOTLB_GRAN(1) | QI_IOTLB_TYPE;
-    QiDesc.High = QI_IOTLB_ADDR(0) | QI_IOTLB_IH(0) | QI_IOTLB_AM(0);
+    QiDesc.Uint64[0] = QI_IOTLB_DID(0) | QI_IOTLB_DR(CAP_READ_DRAIN(mVtdUnitInformation[VtdIndex].CapReg.Uint64)) | QI_IOTLB_DW(CAP_WRITE_DRAIN(mVtdUnitInformation[VtdIndex].CapReg.Uint64)) | QI_IOTLB_GRAN(1) | QI_IOTLB_TYPE;
+    QiDesc.Uint64[1] = QI_IOTLB_ADDR(0) | QI_IOTLB_IH(0) | QI_IOTLB_AM(0);
+    QiDesc.Uint64[2] = 0;
+    QiDesc.Uint64[3] = 0;
 
     return SubmitQueuedInvalidationDescriptor(VtdIndex, &QiDesc);
   }
@@ -504,6 +570,7 @@ ClearGlobalCommandRegisterBits (
   do {
     Reg32 = MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG);
   } while ((Reg32 & BitMask) == BitMask);
+  DEBUG ((DEBUG_INFO, "GSTS_REG : 0x%08x \n", Reg32));
 }
 
 /**
@@ -535,6 +602,7 @@ SetGlobalCommandRegisterBits (
   do {
     Reg32 = MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG);
   } while ((Reg32 & BitMask) == 0);
+  DEBUG ((DEBUG_INFO, "GSTS_REG : 0x%08x \n", Reg32));
 }
 
 /**
@@ -600,22 +668,19 @@ EnableDmar (
       //
       UpdateRootTableAddressRegister (Index, TRUE);
 
+      DEBUG((DEBUG_INFO, "EnableDmar: waiting for RTPS bit to be set... \n"));
+      SetGlobalCommandRegisterBits (VtdUnitBaseAddress, B_GMCD_REG_SRTP);
+
       DEBUG((DEBUG_INFO, "Enable Abort DMA Mode...\n"));
       SetGlobalCommandRegisterBits (VtdUnitBaseAddress, B_GMCD_REG_TE);
 
     } else {
       UpdateRootTableAddressRegister (Index, FALSE);
 
+      DEBUG((DEBUG_INFO, "EnableDmar: waiting for RTPS bit to be set... \n"));
+      SetGlobalCommandRegisterBits (VtdUnitBaseAddress, B_GMCD_REG_SRTP);
     }
 
-    DEBUG((DEBUG_INFO, "EnableDmar: waiting for RTPS bit to be set... \n"));
-    SetGlobalCommandRegisterBits (VtdUnitBaseAddress, B_GMCD_REG_SRTP);
-
-    //
-    // Init DMAr Fault Event and Data registers
-    //
-    MmioRead32 (mVtdUnitInformation[Index].VtdUnitBaseAddress + R_FEDATA_REG);
-
     //
     // Write Buffer Flush before invalidation
     //
@@ -637,6 +702,9 @@ EnableDmar (
       }
 
       UpdateRootTableAddressRegister (Index, FALSE);
+
+      DEBUG((DEBUG_INFO, "EnableDmar: waiting for RTPS bit to be set... \n"));
+      SetGlobalCommandRegisterBits (VtdUnitBaseAddress, B_GMCD_REG_SRTP);
     }
 
     //
diff --git a/Silicon/Intel/IntelSiliconPkg/Include/IndustryStandard/Vtd.h b/Silicon/Intel/IntelSiliconPkg/Include/IndustryStandard/Vtd.h
index 32fbdd02e..3e1b8c3c5 100644
--- a/Silicon/Intel/IntelSiliconPkg/Include/IndustryStandard/Vtd.h
+++ b/Silicon/Intel/IntelSiliconPkg/Include/IndustryStandard/Vtd.h
@@ -259,6 +259,8 @@ typedef union {
 
 #define R_IQA_REG        0x90
 
+#define R_IQERCD_REG     0xB0
+
 #define VTD_PAGE_SHIFT   (12)
 #define VTD_PAGE_SIZE    (1UL << VTD_PAGE_SHIFT)
 #define VTD_PAGE_MASK    (((UINT64)-1) << VTD_PAGE_SHIFT)
@@ -289,13 +291,20 @@ typedef union {
 #define QI_IWD_STATUS_WRITE (((UINT64)1) << 5)
 
 //
-// This is the queued invalidate descriptor.
+// queued invalidation 128-bit descriptor
 //
 typedef struct {
-  UINT64 Low;
-  UINT64 High;
+  UINT64          Low;
+  UINT64          High;
 } QI_DESC;
 
+//
+// queued invalidation 256-bit descriptor
+//
+typedef struct {
+  UINT64          Uint64[4];
+} QI_256_DESC;
+
 typedef union {
   struct {
     UINT8         Minor:4;
@@ -411,6 +420,56 @@ typedef union {
   UINT64     Uint64[2];
 } VTD_FRCD_REG;
 
+typedef union {
+  struct {
+    UINT32   IQEI:4;       // Invalidation Queue Error Info
+    UINT32   Rsvd_4:28;
+    UINT32   ITESID:16;    // Invalidation Time-out Error Source Identifier
+    UINT32   ICESID:16;    // Invalidation Completion Error Source Identifier
+  } Bits;
+  UINT64     Uint64;
+} VTD_IQERCD_REG;
+
+typedef union {
+  struct {
+    UINT64   Rsvd_0:4;
+    UINT64   QH:15;         // Queue Head
+    UINT64   Rsvd_19:45;
+  } Bits128Desc;
+  struct {
+    UINT64   Rsvd_0:4;
+    UINT64   Rsvd_4:1;
+    UINT64   QH:14;         // Queue Head
+    UINT64   Rsvd_19:45;
+  } Bits256Desc;
+  UINT64     Uint64;
+} VTD_IQH_REG;
+
+typedef union {
+  struct {
+    UINT64   Rsvd_0:4;
+    UINT64   QT:15;         // Queue Tail
+    UINT64   Rsvd_19:45;
+  } Bits128Desc;
+  struct {
+    UINT64   Rsvd_0:4;
+    UINT64   Rsvd_4:1;
+    UINT64   QT:14;         // Queue Tail
+    UINT64   Rsvd_19:45;
+  } Bits256Desc;
+  UINT64     Uint64;
+} VTD_IQT_REG;
+
+typedef union {
+  struct {
+    UINT64   QS:3;         // Queue Size
+    UINT64   Rsvd_3:8;
+    UINT64   DW:1;         // Descriptor Width
+    UINT64   IQA:52;       // Invalidation Queue Base Address
+  } Bits;
+  UINT64     Uint64;
+} VTD_IQA_REG;
+
 typedef union {
   struct {
     UINT8    Function:3;
-- 
2.26.2.windows.1


^ permalink raw reply related	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2022-11-30  5:15 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2022-11-30  5:15 [PATCH] IntelSiliconPkg/VTd: Use 256-bit invaildation queue descriptor Sheng Wei
  -- strict thread matches above, loose matches on Subject: below --
2022-11-21  5:43 Sheng Wei

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox