]> git.proxmox.com Git - mirror_edk2.git/blobdiff - IntelSiliconPkg/IntelVTdDxe/TranslationTable.c
IntelSiliconPkg/IntelVTdDxe: Improve performance.
[mirror_edk2.git] / IntelSiliconPkg / IntelVTdDxe / TranslationTable.c
index 961d7cad0ddf734d6962bfedc416e9770d99a9c1..80fc82347e20e375e94acb489caac51df0d4505b 100644 (file)
@@ -124,6 +124,7 @@ CreateContextEntry (
       RootEntry->Bits.ContextTablePointerHi  = (UINT32) RShiftU64 ((UINT64)(UINTN)Buffer, 32);\r
       RootEntry->Bits.Present = 1;\r
       Buffer = (UINT8 *)Buffer + EFI_PAGES_TO_SIZE (ContextPages);\r
+      FlushPageTableMemory (VtdIndex, (UINTN)RootEntry, sizeof(*RootEntry));\r
     }\r
 \r
     ContextEntryTable = (VTD_CONTEXT_ENTRY *)(UINTN)VTD_64BITS_ADDRESS(RootEntry->Bits.ContextTablePointerLo, RootEntry->Bits.ContextTablePointerHi) ;\r
@@ -142,6 +143,7 @@ CreateContextEntry (
       ContextEntry->Bits.AddressWidth = 0x2;\r
       break;\r
     }\r
+    FlushPageTableMemory (VtdIndex, (UINTN)ContextEntry, sizeof(*ContextEntry));\r
   }\r
 \r
   return EFI_SUCCESS;\r
@@ -250,8 +252,11 @@ CreateSecondLevelPagingEntryTable (
           goto Done;\r
         }\r
       }\r
+      FlushPageTableMemory (VtdIndex, (UINTN)Lvl2PtEntry, SIZE_4KB);\r
     }\r
+    FlushPageTableMemory (VtdIndex, (UINTN)&Lvl3PtEntry[Lvl3Start], (UINTN)&Lvl3PtEntry[Lvl3End + 1] - (UINTN)&Lvl3PtEntry[Lvl3Start]);\r
   }\r
+  FlushPageTableMemory (VtdIndex, (UINTN)&Lvl4PtEntry[Lvl4Start], (UINTN)&Lvl4PtEntry[Lvl4End + 1] - (UINTN)&Lvl4PtEntry[Lvl4Start]);\r
 \r
 Done:\r
   return SecondLevelPagingEntry;\r
@@ -429,9 +434,10 @@ InvalidatePageEntry (
   IN UINTN                 VtdIndex\r
   )\r
 {\r
-  if (mVtdUnitInformation[VtdIndex].HasDirtyPages) {\r
+  if (mVtdUnitInformation[VtdIndex].HasDirtyContext || mVtdUnitInformation[VtdIndex].HasDirtyPages) {\r
     InvalidateVtdIOTLBGlobal (VtdIndex);\r
   }\r
+  mVtdUnitInformation[VtdIndex].HasDirtyContext = FALSE;\r
   mVtdUnitInformation[VtdIndex].HasDirtyPages = FALSE;\r
 }\r
 \r
@@ -498,6 +504,7 @@ PageAttributeToLength (
 /**\r
   Return page table entry to match the address.\r
 \r
+  @param[in]   VtdIndex                 The index used to identify a VTd engine.\r
   @param[in]   SecondLevelPagingEntry   The second level paging entry in VTd table for the device.\r
   @param[in]   Address                  The address to be checked.\r
   @param[out]  PageAttributes           The page attribute of the page entry.\r
@@ -506,6 +513,7 @@ PageAttributeToLength (
 **/\r
 VOID *\r
 GetSecondLevelPageTableEntry (\r
+  IN  UINTN                         VtdIndex,\r
   IN  VTD_SECOND_LEVEL_PAGING_ENTRY *SecondLevelPagingEntry,\r
   IN  PHYSICAL_ADDRESS              Address,\r
   OUT PAGE_ATTRIBUTE                *PageAttribute\r
@@ -535,6 +543,7 @@ GetSecondLevelPageTableEntry (
       return NULL;\r
     }\r
     SetSecondLevelPagingEntryAttribute ((VTD_SECOND_LEVEL_PAGING_ENTRY *)&L4PageTable[Index4], EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE);\r
+    FlushPageTableMemory (VtdIndex, (UINTN)&L4PageTable[Index4], sizeof(L4PageTable[Index4]));\r
   }\r
 \r
   L3PageTable = (UINT64 *)(UINTN)(L4PageTable[Index4] & PAGING_4K_ADDRESS_MASK_64);\r
@@ -547,6 +556,7 @@ GetSecondLevelPageTableEntry (
       return NULL;\r
     }\r
     SetSecondLevelPagingEntryAttribute ((VTD_SECOND_LEVEL_PAGING_ENTRY *)&L3PageTable[Index3], EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE);\r
+    FlushPageTableMemory (VtdIndex, (UINTN)&L3PageTable[Index3], sizeof(L3PageTable[Index3]));\r
   }\r
   if ((L3PageTable[Index3] & VTD_PG_PS) != 0) {\r
     // 1G\r
@@ -559,6 +569,7 @@ GetSecondLevelPageTableEntry (
     L2PageTable[Index2] = Address & PAGING_2M_ADDRESS_MASK_64;\r
     SetSecondLevelPagingEntryAttribute ((VTD_SECOND_LEVEL_PAGING_ENTRY *)&L2PageTable[Index2], 0);\r
     L2PageTable[Index2] |= VTD_PG_PS;\r
+    FlushPageTableMemory (VtdIndex, (UINTN)&L2PageTable[Index2], sizeof(L2PageTable[Index2]));\r
   }\r
   if ((L2PageTable[Index2] & VTD_PG_PS) != 0) {\r
     // 2M\r
@@ -579,12 +590,14 @@ GetSecondLevelPageTableEntry (
 /**\r
   Modify memory attributes of page entry.\r
 \r
+  @param[in]   VtdIndex         The index used to identify a VTd engine.\r
   @param[in]   PageEntry        The page entry.\r
   @param[in]   IoMmuAccess      The IOMMU access.\r
   @param[out]  IsModified       TRUE means page table modified. FALSE means page table not modified.\r
 **/\r
 VOID\r
 ConvertSecondLevelPageEntryAttribute (\r
+  IN  UINTN                             VtdIndex,\r
   IN  VTD_SECOND_LEVEL_PAGING_ENTRY     *PageEntry,\r
   IN  UINT64                            IoMmuAccess,\r
   OUT BOOLEAN                           *IsModified\r
@@ -595,6 +608,7 @@ ConvertSecondLevelPageEntryAttribute (
 \r
   CurrentPageEntry = PageEntry->Uint64;\r
   SetSecondLevelPagingEntryAttribute (PageEntry, IoMmuAccess);\r
+  FlushPageTableMemory (VtdIndex, (UINTN)PageEntry, sizeof(*PageEntry));\r
   NewPageEntry = PageEntry->Uint64;\r
   if (CurrentPageEntry != NewPageEntry) {\r
     *IsModified = TRUE;\r
@@ -639,6 +653,7 @@ NeedSplitPage (
 /**\r
   This function splits one page entry to small page entries.\r
 \r
+  @param[in]  VtdIndex         The index used to identify a VTd engine.\r
   @param[in]  PageEntry        The page entry to be splitted.\r
   @param[in]  PageAttribute    The page attribute of the page entry.\r
   @param[in]  SplitAttribute   How to split the page entry.\r
@@ -649,6 +664,7 @@ NeedSplitPage (
 **/\r
 RETURN_STATUS\r
 SplitSecondLevelPage (\r
+  IN  UINTN                             VtdIndex,\r
   IN  VTD_SECOND_LEVEL_PAGING_ENTRY     *PageEntry,\r
   IN  PAGE_ATTRIBUTE                    PageAttribute,\r
   IN  PAGE_ATTRIBUTE                    SplitAttribute\r
@@ -675,8 +691,11 @@ SplitSecondLevelPage (
       for (Index = 0; Index < SIZE_4KB / sizeof(UINT64); Index++) {\r
         NewPageEntry[Index] = (BaseAddress + SIZE_4KB * Index) | (PageEntry->Uint64 & PAGE_PROGATE_BITS);\r
       }\r
+      FlushPageTableMemory (VtdIndex, (UINTN)NewPageEntry, SIZE_4KB);\r
+\r
       PageEntry->Uint64 = (UINT64)(UINTN)NewPageEntry;\r
       SetSecondLevelPagingEntryAttribute (PageEntry, EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE);\r
+      FlushPageTableMemory (VtdIndex, (UINTN)PageEntry, sizeof(*PageEntry));\r
       return RETURN_SUCCESS;\r
     } else {\r
       return RETURN_UNSUPPORTED;\r
@@ -697,8 +716,11 @@ SplitSecondLevelPage (
       for (Index = 0; Index < SIZE_4KB / sizeof(UINT64); Index++) {\r
         NewPageEntry[Index] = (BaseAddress + SIZE_2MB * Index) | VTD_PG_PS | (PageEntry->Uint64 & PAGE_PROGATE_BITS);\r
       }\r
+      FlushPageTableMemory (VtdIndex, (UINTN)NewPageEntry, SIZE_4KB);\r
+\r
       PageEntry->Uint64 = (UINT64)(UINTN)NewPageEntry;\r
       SetSecondLevelPagingEntryAttribute (PageEntry, EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE);\r
+      FlushPageTableMemory (VtdIndex, (UINTN)PageEntry, sizeof(*PageEntry));\r
       return RETURN_SUCCESS;\r
     } else {\r
       return RETURN_UNSUPPORTED;\r
@@ -730,6 +752,7 @@ SplitSecondLevelPage (
 EFI_STATUS\r
 SetSecondLevelPagingAttribute (\r
   IN UINTN                         VtdIndex,\r
+  IN UINT16                        DomainIdentifier,\r
   IN VTD_SECOND_LEVEL_PAGING_ENTRY *SecondLevelPagingEntry,\r
   IN UINT64                        BaseAddress,\r
   IN UINT64                        Length,\r
@@ -756,7 +779,7 @@ SetSecondLevelPagingAttribute (
   }\r
 \r
   while (Length != 0) {\r
-    PageEntry = GetSecondLevelPageTableEntry (SecondLevelPagingEntry, BaseAddress, &PageAttribute);\r
+    PageEntry = GetSecondLevelPageTableEntry (VtdIndex, SecondLevelPagingEntry, BaseAddress, &PageAttribute);\r
     if (PageEntry == NULL) {\r
       DEBUG ((DEBUG_ERROR, "PageEntry - NULL\n"));\r
       return RETURN_UNSUPPORTED;\r
@@ -764,7 +787,7 @@ SetSecondLevelPagingAttribute (
     PageEntryLength = PageAttributeToLength (PageAttribute);\r
     SplitAttribute = NeedSplitPage (BaseAddress, Length, PageAttribute);\r
     if (SplitAttribute == PageNone) {\r
-      ConvertSecondLevelPageEntryAttribute (PageEntry, IoMmuAccess, &IsEntryModified);\r
+      ConvertSecondLevelPageEntryAttribute (VtdIndex, PageEntry, IoMmuAccess, &IsEntryModified);\r
       if (IsEntryModified) {\r
         mVtdUnitInformation[VtdIndex].HasDirtyPages = TRUE;\r
       }\r
@@ -774,7 +797,7 @@ SetSecondLevelPagingAttribute (
       BaseAddress += PageEntryLength;\r
       Length -= PageEntryLength;\r
     } else {\r
-      Status = SplitSecondLevelPage (PageEntry, PageAttribute, SplitAttribute);\r
+      Status = SplitSecondLevelPage (VtdIndex, PageEntry, PageAttribute, SplitAttribute);\r
       if (RETURN_ERROR (Status)) {\r
         DEBUG ((DEBUG_ERROR, "SplitSecondLevelPage - %r\n", Status));\r
         return RETURN_UNSUPPORTED;\r
@@ -787,8 +810,6 @@ SetSecondLevelPagingAttribute (
     }\r
   }\r
 \r
-  InvalidatePageEntry (VtdIndex);\r
-\r
   return EFI_SUCCESS;\r
 }\r
 \r
@@ -814,6 +835,7 @@ SetSecondLevelPagingAttribute (
 EFI_STATUS\r
 SetPageAttribute (\r
   IN UINTN                         VtdIndex,\r
+  IN UINT16                        DomainIdentifier,\r
   IN VTD_SECOND_LEVEL_PAGING_ENTRY *SecondLevelPagingEntry,\r
   IN UINT64                        BaseAddress,\r
   IN UINT64                        Length,\r
@@ -823,7 +845,7 @@ SetPageAttribute (
   EFI_STATUS Status;\r
   Status = EFI_NOT_FOUND;\r
   if (SecondLevelPagingEntry != NULL) {\r
-    Status = SetSecondLevelPagingAttribute (VtdIndex, SecondLevelPagingEntry, BaseAddress, Length, IoMmuAccess);\r
+    Status = SetSecondLevelPagingAttribute (VtdIndex, DomainIdentifier, SecondLevelPagingEntry, BaseAddress, Length, IoMmuAccess);\r
   }\r
   return Status;\r
 }\r
@@ -862,6 +884,8 @@ SetAccessAttribute (
   VTD_CONTEXT_ENTRY             *ContextEntry;\r
   VTD_SECOND_LEVEL_PAGING_ENTRY *SecondLevelPagingEntry;\r
   UINT64                        Pt;\r
+  UINTN                         PciDescriptorIndex;\r
+  UINT16                        DomainIdentifier;\r
 \r
   SecondLevelPagingEntry = NULL;\r
 \r
@@ -873,6 +897,13 @@ SetAccessAttribute (
     return EFI_DEVICE_ERROR;\r
   }\r
 \r
+  PciDescriptorIndex = GetPciDescriptor (VtdIndex, Segment, SourceId);\r
+  mVtdUnitInformation[VtdIndex].PciDeviceInfo.AccessCount[PciDescriptorIndex]++;\r
+  //\r
+  // DomainId should not be 0.\r
+  //\r
+  DomainIdentifier = (UINT16)(PciDescriptorIndex + 1);\r
+\r
   if (ExtContextEntry != NULL) {\r
     if (ExtContextEntry->Bits.Present == 0) {\r
       SecondLevelPagingEntry = CreateSecondLevelPagingEntry (VtdIndex, 0);\r
@@ -881,9 +912,11 @@ SetAccessAttribute (
 \r
       ExtContextEntry->Bits.SecondLevelPageTranslationPointerLo = (UINT32) Pt;\r
       ExtContextEntry->Bits.SecondLevelPageTranslationPointerHi = (UINT32) RShiftU64(Pt, 20);\r
-      ExtContextEntry->Bits.DomainIdentifier = (UINT16) GetPciDescriptor (VtdIndex, Segment, SourceId);\r
+      ExtContextEntry->Bits.DomainIdentifier = DomainIdentifier;\r
       ExtContextEntry->Bits.Present = 1;\r
+      FlushPageTableMemory (VtdIndex, (UINTN)ExtContextEntry, sizeof(*ExtContextEntry));\r
       DumpDmarExtContextEntryTable (mVtdUnitInformation[VtdIndex].ExtRootEntryTable);\r
+      mVtdUnitInformation[VtdIndex].HasDirtyContext = TRUE;\r
     } else {\r
       SecondLevelPagingEntry = (VOID *)(UINTN)VTD_64BITS_ADDRESS(ExtContextEntry->Bits.SecondLevelPageTranslationPointerLo, ExtContextEntry->Bits.SecondLevelPageTranslationPointerHi);\r
       DEBUG ((DEBUG_VERBOSE,"SecondLevelPagingEntry - 0x%x (S%04x B%02x D%02x F%02x)\n", SecondLevelPagingEntry, Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function));\r
@@ -896,9 +929,11 @@ SetAccessAttribute (
 \r
       ContextEntry->Bits.SecondLevelPageTranslationPointerLo = (UINT32) Pt;\r
       ContextEntry->Bits.SecondLevelPageTranslationPointerHi = (UINT32) RShiftU64(Pt, 20);\r
-      ContextEntry->Bits.DomainIdentifier = (UINT16) GetPciDescriptor (VtdIndex, Segment, SourceId);\r
+      ContextEntry->Bits.DomainIdentifier = DomainIdentifier;\r
       ContextEntry->Bits.Present = 1;\r
+      FlushPageTableMemory (VtdIndex, (UINTN)ContextEntry, sizeof(*ContextEntry));\r
       DumpDmarContextEntryTable (mVtdUnitInformation[VtdIndex].RootEntryTable);\r
+      mVtdUnitInformation[VtdIndex].HasDirtyContext = TRUE;\r
     } else {\r
       SecondLevelPagingEntry = (VOID *)(UINTN)VTD_64BITS_ADDRESS(ContextEntry->Bits.SecondLevelPageTranslationPointerLo, ContextEntry->Bits.SecondLevelPageTranslationPointerHi);\r
       DEBUG ((DEBUG_VERBOSE,"SecondLevelPagingEntry - 0x%x (S%04x B%02x D%02x F%02x)\n", SecondLevelPagingEntry, Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function));\r
@@ -911,6 +946,7 @@ SetAccessAttribute (
   if (SecondLevelPagingEntry != mVtdUnitInformation[VtdIndex].FixedSecondLevelPagingEntry) {\r
     Status = SetPageAttribute (\r
                VtdIndex,\r
+               DomainIdentifier,\r
                SecondLevelPagingEntry,\r
                BaseAddress,\r
                Length,\r
@@ -922,6 +958,8 @@ SetAccessAttribute (
     }\r
   }\r
 \r
+  InvalidatePageEntry (VtdIndex);\r
+\r
   return EFI_SUCCESS;\r
 }\r
 \r
@@ -965,11 +1003,13 @@ AlwaysEnablePageAttribute (
     ExtContextEntry->Bits.SecondLevelPageTranslationPointerHi = (UINT32) RShiftU64(Pt, 20);\r
     ExtContextEntry->Bits.DomainIdentifier = ((1 << (UINT8)((UINTN)mVtdUnitInformation[VtdIndex].CapReg.Bits.ND * 2 + 4)) - 1);\r
     ExtContextEntry->Bits.Present = 1;\r
+    FlushPageTableMemory (VtdIndex, (UINTN)ExtContextEntry, sizeof(*ExtContextEntry));\r
   } else if (ContextEntry != NULL) {\r
     ContextEntry->Bits.SecondLevelPageTranslationPointerLo = (UINT32) Pt;\r
     ContextEntry->Bits.SecondLevelPageTranslationPointerHi = (UINT32) RShiftU64(Pt, 20);\r
     ContextEntry->Bits.DomainIdentifier = ((1 << (UINT8)((UINTN)mVtdUnitInformation[VtdIndex].CapReg.Bits.ND * 2 + 4)) - 1);\r
     ContextEntry->Bits.Present = 1;\r
+    FlushPageTableMemory (VtdIndex, (UINTN)ContextEntry, sizeof(*ContextEntry));\r
   }\r
 \r
   return EFI_SUCCESS;\r