VtdReg.c 34 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004
  1. /** @file
  2. Copyright (c) 2017 - 2019, Intel Corporation. All rights reserved.<BR>
  3. SPDX-License-Identifier: BSD-2-Clause-Patent
  4. **/
  5. #include "DmaProtection.h"
  6. UINTN mVtdUnitNumber;
  7. VTD_UNIT_INFORMATION *mVtdUnitInformation;
  8. BOOLEAN mVtdEnabled;
  9. /**
  10. Flush VTD page table and context table memory.
  11. This action is to make sure the IOMMU engine can get final data in memory.
  12. @param[in] VtdIndex The index used to identify a VTd engine.
  13. @param[in] Base The base address of memory to be flushed.
  14. @param[in] Size The size of memory in bytes to be flushed.
  15. **/
  16. VOID
  17. FlushPageTableMemory (
  18. IN UINTN VtdIndex,
  19. IN UINTN Base,
  20. IN UINTN Size
  21. )
  22. {
  23. if (mVtdUnitInformation[VtdIndex].ECapReg.Bits.C == 0) {
  24. WriteBackDataCacheRange ((VOID *)Base, Size);
  25. }
  26. }
  27. /**
  28. Flush VTd engine write buffer.
  29. @param[in] VtdIndex The index used to identify a VTd engine.
  30. **/
  31. VOID
  32. FlushWriteBuffer (
  33. IN UINTN VtdIndex
  34. )
  35. {
  36. UINT32 Reg32;
  37. if (mVtdUnitInformation[VtdIndex].CapReg.Bits.RWBF != 0) {
  38. Reg32 = MmioRead32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_GSTS_REG);
  39. MmioWrite32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_GCMD_REG, Reg32 | B_GMCD_REG_WBF);
  40. do {
  41. Reg32 = MmioRead32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_GSTS_REG);
  42. } while ((Reg32 & B_GSTS_REG_WBF) != 0);
  43. }
  44. }
  45. /**
  46. Perpare cache invalidation interface.
  47. @param[in] VtdIndex The index used to identify a VTd engine.
  48. @retval EFI_SUCCESS The operation was successful.
  49. @retval EFI_UNSUPPORTED Invalidation method is not supported.
  50. @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
  51. **/
  52. EFI_STATUS
  53. PerpareCacheInvalidationInterface (
  54. IN UINTN VtdIndex
  55. )
  56. {
  57. UINT32 Reg32;
  58. VTD_IQA_REG IqaReg;
  59. VTD_UNIT_INFORMATION *VTdUnitInfo;
  60. UINTN VtdUnitBaseAddress;
  61. VTdUnitInfo = &mVtdUnitInformation[VtdIndex];
  62. VtdUnitBaseAddress = VTdUnitInfo->VtdUnitBaseAddress;
  63. if (VTdUnitInfo->VerReg.Bits.Major <= 5) {
  64. VTdUnitInfo->EnableQueuedInvalidation = 0;
  65. DEBUG ((DEBUG_INFO, "Use Register-based Invalidation Interface for engine [%d]\n", VtdIndex));
  66. return EFI_SUCCESS;
  67. }
  68. if (VTdUnitInfo->ECapReg.Bits.QI == 0) {
  69. DEBUG ((DEBUG_ERROR, "Hardware does not support queued invalidations interface for engine [%d]\n", VtdIndex));
  70. return EFI_UNSUPPORTED;
  71. }
  72. VTdUnitInfo->EnableQueuedInvalidation = 1;
  73. DEBUG ((DEBUG_INFO, "Use Queued Invalidation Interface for engine [%d]\n", VtdIndex));
  74. Reg32 = MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG);
  75. if ((Reg32 & B_GSTS_REG_QIES) != 0) {
  76. DEBUG ((DEBUG_ERROR,"Queued Invalidation Interface was enabled.\n"));
  77. Reg32 &= (~B_GSTS_REG_QIES);
  78. MmioWrite32 (VtdUnitBaseAddress + R_GCMD_REG, Reg32);
  79. do {
  80. Reg32 = MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG);
  81. } while ((Reg32 & B_GSTS_REG_QIES) != 0);
  82. }
  83. //
  84. // Initialize the Invalidation Queue Tail Register to zero.
  85. //
  86. MmioWrite64 (VtdUnitBaseAddress + R_IQT_REG, 0);
  87. //
  88. // Setup the IQ address, size and descriptor width through the Invalidation Queue Address Register
  89. //
  90. if (VTdUnitInfo->QiDescBuffer == NULL) {
  91. VTdUnitInfo->QiDescBufferSize = (sizeof (QI_256_DESC) * ((UINTN) 1 << (VTD_INVALIDATION_QUEUE_SIZE + 7)));
  92. VTdUnitInfo->QiDescBuffer = AllocatePages (EFI_SIZE_TO_PAGES (VTdUnitInfo->QiDescBufferSize));
  93. if (VTdUnitInfo->QiDescBuffer == NULL) {
  94. DEBUG ((DEBUG_ERROR,"Could not Alloc Invalidation Queue Buffer.\n"));
  95. return EFI_OUT_OF_RESOURCES;
  96. }
  97. }
  98. DEBUG ((DEBUG_INFO, "Invalidation Queue Buffer Size : %d\n", VTdUnitInfo->QiDescBufferSize));
  99. //
  100. // 4KB Aligned address
  101. //
  102. IqaReg.Uint64 = (UINT64) (UINTN) VTdUnitInfo->QiDescBuffer;
  103. IqaReg.Bits.DW = VTD_QUEUED_INVALIDATION_DESCRIPTOR_WIDTH;
  104. IqaReg.Bits.QS = VTD_INVALIDATION_QUEUE_SIZE;
  105. MmioWrite64 (VtdUnitBaseAddress + R_IQA_REG, IqaReg.Uint64);
  106. IqaReg.Uint64 = MmioRead64 (VtdUnitBaseAddress + R_IQA_REG);
  107. DEBUG ((DEBUG_INFO, "IQA_REG = 0x%lx, IQH_REG = 0x%lx\n", IqaReg.Uint64, MmioRead64 (VtdUnitBaseAddress + R_IQH_REG)));
  108. //
  109. // Enable the queued invalidation interface through the Global Command Register.
  110. // When enabled, hardware sets the QIES field in the Global Status Register.
  111. //
  112. Reg32 = MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG);
  113. Reg32 |= B_GMCD_REG_QIE;
  114. MmioWrite32 (VtdUnitBaseAddress + R_GCMD_REG, Reg32);
  115. DEBUG ((DEBUG_INFO, "Enable Queued Invalidation Interface. GCMD_REG = 0x%x\n", Reg32));
  116. do {
  117. Reg32 = MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG);
  118. } while ((Reg32 & B_GSTS_REG_QIES) == 0);
  119. return EFI_SUCCESS;
  120. }
  121. /**
  122. Disable queued invalidation interface.
  123. @param[in] VtdIndex The index used to identify a VTd engine.
  124. **/
  125. VOID
  126. DisableQueuedInvalidationInterface (
  127. IN UINTN VtdIndex
  128. )
  129. {
  130. UINT32 Reg32;
  131. VTD_UNIT_INFORMATION *VTdUnitInfo;
  132. VTdUnitInfo = &mVtdUnitInformation[VtdIndex];
  133. if (VTdUnitInfo->EnableQueuedInvalidation != 0) {
  134. Reg32 = MmioRead32 (VTdUnitInfo->VtdUnitBaseAddress + R_GSTS_REG);
  135. Reg32 &= (~B_GMCD_REG_QIE);
  136. MmioWrite32 (VTdUnitInfo->VtdUnitBaseAddress + R_GCMD_REG, Reg32);
  137. DEBUG ((DEBUG_INFO, "Disable Queued Invalidation Interface. GCMD_REG = 0x%x\n", Reg32));
  138. do {
  139. Reg32 = MmioRead32 (VTdUnitInfo->VtdUnitBaseAddress + R_GSTS_REG);
  140. } while ((Reg32 & B_GSTS_REG_QIES) != 0);
  141. if (VTdUnitInfo->QiDescBuffer != NULL) {
  142. FreePages(VTdUnitInfo->QiDescBuffer, EFI_SIZE_TO_PAGES (VTdUnitInfo->QiDescBufferSize));
  143. VTdUnitInfo->QiDescBuffer = NULL;
  144. VTdUnitInfo->QiDescBufferSize = 0;
  145. }
  146. mVtdUnitInformation[VtdIndex].EnableQueuedInvalidation = 0;
  147. }
  148. }
  149. /**
  150. Check Queued Invalidation Fault.
  151. @param[in] VtdIndex The index used to identify a VTd engine.
  152. @retval EFI_SUCCESS The operation was successful.
  153. @retval RETURN_DEVICE_ERROR A fault is detected.
  154. **/
  155. EFI_STATUS
  156. QueuedInvalidationCheckFault (
  157. IN UINTN VtdIndex
  158. )
  159. {
  160. UINT32 FaultReg;
  161. VTD_IQERCD_REG IqercdReg;
  162. FaultReg = MmioRead32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_FSTS_REG);
  163. if (FaultReg & (B_FSTS_REG_IQE | B_FSTS_REG_ITE | B_FSTS_REG_ICE)) {
  164. IqercdReg.Uint64 = MmioRead64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_IQERCD_REG);
  165. DEBUG((DEBUG_ERROR, "Detect Queue Invalidation Error [0x%08x] - IQERCD [0x%016lx]\n", FaultReg, IqercdReg.Uint64));
  166. MmioWrite32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_FSTS_REG, FaultReg);
  167. return RETURN_DEVICE_ERROR;
  168. }
  169. return EFI_SUCCESS;
  170. }
  171. /**
  172. Submit the queued invalidation descriptor to the remapping
  173. hardware unit and wait for its completion.
  174. @param[in] VtdIndex The index used to identify a VTd engine.
  175. @param[in] Desc The invalidate descriptor
  176. @retval EFI_SUCCESS The operation was successful.
  177. @retval RETURN_DEVICE_ERROR A fault is detected.
  178. @retval EFI_INVALID_PARAMETER Parameter is invalid.
  179. **/
  180. EFI_STATUS
  181. SubmitQueuedInvalidationDescriptor (
  182. IN UINTN VtdIndex,
  183. IN QI_256_DESC *Desc
  184. )
  185. {
  186. EFI_STATUS Status;
  187. UINTN VtdUnitBaseAddress;
  188. UINTN QueueSize;
  189. UINTN QueueTail;
  190. UINTN QueueHead;
  191. QI_DESC *Qi128Desc;
  192. QI_256_DESC *Qi256Desc;
  193. VTD_IQA_REG IqaReg;
  194. VTD_IQT_REG IqtReg;
  195. VTD_IQH_REG IqhReg;
  196. if (Desc == NULL) {
  197. return EFI_INVALID_PARAMETER;
  198. }
  199. VtdUnitBaseAddress = mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress;
  200. IqaReg.Uint64 = MmioRead64 (VtdUnitBaseAddress + R_IQA_REG);
  201. if (IqaReg.Bits.IQA == 0) {
  202. DEBUG ((DEBUG_ERROR,"Invalidation Queue Buffer not ready [0x%lx]\n", IqaReg.Uint64));
  203. return EFI_NOT_READY;
  204. }
  205. IqtReg.Uint64 = MmioRead64 (VtdUnitBaseAddress + R_IQT_REG);
  206. if (IqaReg.Bits.DW == 0) {
  207. //
  208. // 128-bit descriptor
  209. //
  210. QueueSize = (UINTN) (1 << (IqaReg.Bits.QS + 8));
  211. Qi128Desc = (QI_DESC *) (UINTN) (IqaReg.Bits.IQA << VTD_PAGE_SHIFT);
  212. QueueTail = (UINTN) IqtReg.Bits128Desc.QT;
  213. Qi128Desc += QueueTail;
  214. Qi128Desc->Low = Desc->Uint64[0];
  215. Qi128Desc->High = Desc->Uint64[1];
  216. FlushPageTableMemory (VtdIndex, (UINTN) Qi128Desc, sizeof(QI_DESC));
  217. QueueTail = (QueueTail + 1) % QueueSize;
  218. DEBUG ((DEBUG_VERBOSE, "[0x%x] Submit QI Descriptor 0x%x [0x%016lx, 0x%016lx]\n",
  219. VtdUnitBaseAddress,
  220. QueueTail,
  221. Desc->Uint64[0],
  222. Desc->Uint64[1]));
  223. IqtReg.Bits128Desc.QT = QueueTail;
  224. } else {
  225. //
  226. // 256-bit descriptor
  227. //
  228. QueueSize = (UINTN) (1 << (IqaReg.Bits.QS + 7));
  229. Qi256Desc = (QI_256_DESC *) (UINTN) (IqaReg.Bits.IQA << VTD_PAGE_SHIFT);
  230. QueueTail = (UINTN) IqtReg.Bits256Desc.QT;
  231. Qi256Desc += QueueTail;
  232. Qi256Desc->Uint64[0] = Desc->Uint64[0];
  233. Qi256Desc->Uint64[1] = Desc->Uint64[1];
  234. Qi256Desc->Uint64[2] = Desc->Uint64[2];
  235. Qi256Desc->Uint64[3] = Desc->Uint64[3];
  236. FlushPageTableMemory (VtdIndex, (UINTN) Qi256Desc, sizeof(QI_256_DESC));
  237. QueueTail = (QueueTail + 1) % QueueSize;
  238. DEBUG ((DEBUG_VERBOSE, "[0x%x] Submit QI Descriptor 0x%x [0x%016lx, 0x%016lx, 0x%016lx, 0x%016lx]\n",
  239. VtdUnitBaseAddress,
  240. QueueTail,
  241. Desc->Uint64[0],
  242. Desc->Uint64[1],
  243. Desc->Uint64[2],
  244. Desc->Uint64[3]));
  245. IqtReg.Bits256Desc.QT = QueueTail;
  246. }
  247. //
  248. // Update the HW tail register indicating the presence of new descriptors.
  249. //
  250. MmioWrite64 (VtdUnitBaseAddress + R_IQT_REG, IqtReg.Uint64);
  251. Status = EFI_SUCCESS;
  252. do {
  253. Status = QueuedInvalidationCheckFault(VtdIndex);
  254. if (Status != EFI_SUCCESS) {
  255. DEBUG((DEBUG_ERROR,"Detect Queued Invalidation Fault.\n"));
  256. break;
  257. }
  258. IqhReg.Uint64 = MmioRead64 (VtdUnitBaseAddress + R_IQH_REG);
  259. if (IqaReg.Bits.DW == 0) {
  260. QueueHead = (UINTN) IqhReg.Bits128Desc.QH;
  261. } else {
  262. QueueHead = (UINTN) IqhReg.Bits256Desc.QH;
  263. }
  264. } while (QueueTail != QueueHead);
  265. return Status;
  266. }
  267. /**
  268. Invalidate VTd context cache.
  269. @param[in] VtdIndex The index used to identify a VTd engine.
  270. **/
  271. EFI_STATUS
  272. InvalidateContextCache (
  273. IN UINTN VtdIndex
  274. )
  275. {
  276. UINT64 Reg64;
  277. QI_256_DESC QiDesc;
  278. if (mVtdUnitInformation[VtdIndex].EnableQueuedInvalidation == 0) {
  279. //
  280. // Register-based Invalidation
  281. //
  282. Reg64 = MmioRead64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_CCMD_REG);
  283. if ((Reg64 & B_CCMD_REG_ICC) != 0) {
  284. DEBUG ((DEBUG_ERROR,"ERROR: InvalidateContextCache: B_CCMD_REG_ICC is set for VTD(%d)\n",VtdIndex));
  285. return EFI_DEVICE_ERROR;
  286. }
  287. Reg64 &= ((~B_CCMD_REG_ICC) & (~B_CCMD_REG_CIRG_MASK));
  288. Reg64 |= (B_CCMD_REG_ICC | V_CCMD_REG_CIRG_GLOBAL);
  289. MmioWrite64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_CCMD_REG, Reg64);
  290. do {
  291. Reg64 = MmioRead64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_CCMD_REG);
  292. } while ((Reg64 & B_CCMD_REG_ICC) != 0);
  293. } else {
  294. //
  295. // Queued Invalidation
  296. //
  297. QiDesc.Uint64[0] = QI_CC_FM(0) | QI_CC_SID(0) | QI_CC_DID(0) | QI_CC_GRAN(1) | QI_CC_TYPE;
  298. QiDesc.Uint64[1] = 0;
  299. QiDesc.Uint64[2] = 0;
  300. QiDesc.Uint64[3] = 0;
  301. return SubmitQueuedInvalidationDescriptor(VtdIndex, &QiDesc);
  302. }
  303. return EFI_SUCCESS;
  304. }
  305. /**
  306. Invalidate VTd IOTLB.
  307. @param[in] VtdIndex The index used to identify a VTd engine.
  308. **/
  309. EFI_STATUS
  310. InvalidateIOTLB (
  311. IN UINTN VtdIndex
  312. )
  313. {
  314. UINT64 Reg64;
  315. QI_256_DESC QiDesc;
  316. if (mVtdUnitInformation[VtdIndex].EnableQueuedInvalidation == 0) {
  317. //
  318. // Register-based Invalidation
  319. //
  320. Reg64 = MmioRead64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + (mVtdUnitInformation[VtdIndex].ECapReg.Bits.IRO * 16) + R_IOTLB_REG);
  321. if ((Reg64 & B_IOTLB_REG_IVT) != 0) {
  322. DEBUG ((DEBUG_ERROR,"ERROR: InvalidateIOTLB: B_IOTLB_REG_IVT is set for VTD(%d)\n", VtdIndex));
  323. return EFI_DEVICE_ERROR;
  324. }
  325. Reg64 &= ((~B_IOTLB_REG_IVT) & (~B_IOTLB_REG_IIRG_MASK));
  326. Reg64 |= (B_IOTLB_REG_IVT | V_IOTLB_REG_IIRG_GLOBAL);
  327. MmioWrite64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + (mVtdUnitInformation[VtdIndex].ECapReg.Bits.IRO * 16) + R_IOTLB_REG, Reg64);
  328. do {
  329. Reg64 = MmioRead64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + (mVtdUnitInformation[VtdIndex].ECapReg.Bits.IRO * 16) + R_IOTLB_REG);
  330. } while ((Reg64 & B_IOTLB_REG_IVT) != 0);
  331. } else {
  332. //
  333. // Queued Invalidation
  334. //
  335. 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;
  336. QiDesc.Uint64[1] = QI_IOTLB_ADDR(0) | QI_IOTLB_IH(0) | QI_IOTLB_AM(0);
  337. QiDesc.Uint64[2] = 0;
  338. QiDesc.Uint64[3] = 0;
  339. return SubmitQueuedInvalidationDescriptor(VtdIndex, &QiDesc);
  340. }
  341. return EFI_SUCCESS;
  342. }
  343. /**
  344. Invalid VTd global IOTLB.
  345. @param[in] VtdIndex The index of VTd engine.
  346. @retval EFI_SUCCESS VTd global IOTLB is invalidated.
  347. @retval EFI_DEVICE_ERROR VTd global IOTLB is not invalidated.
  348. **/
  349. EFI_STATUS
  350. InvalidateVtdIOTLBGlobal (
  351. IN UINTN VtdIndex
  352. )
  353. {
  354. if (!mVtdEnabled) {
  355. return EFI_SUCCESS;
  356. }
  357. DEBUG((DEBUG_VERBOSE, "InvalidateVtdIOTLBGlobal(%d)\n", VtdIndex));
  358. //
  359. // Write Buffer Flush before invalidation
  360. //
  361. FlushWriteBuffer (VtdIndex);
  362. //
  363. // Invalidate the context cache
  364. //
  365. if (mVtdUnitInformation[VtdIndex].HasDirtyContext) {
  366. InvalidateContextCache (VtdIndex);
  367. }
  368. //
  369. // Invalidate the IOTLB cache
  370. //
  371. if (mVtdUnitInformation[VtdIndex].HasDirtyContext || mVtdUnitInformation[VtdIndex].HasDirtyPages) {
  372. InvalidateIOTLB (VtdIndex);
  373. }
  374. return EFI_SUCCESS;
  375. }
  376. /**
  377. Prepare VTD configuration.
  378. **/
  379. VOID
  380. PrepareVtdConfig (
  381. VOID
  382. )
  383. {
  384. UINTN Index;
  385. UINTN DomainNumber;
  386. EFI_STATUS Status;
  387. for (Index = 0; Index < mVtdUnitNumber; Index++) {
  388. DEBUG ((DEBUG_INFO, "Dump VTd Capability (%d)\n", Index));
  389. mVtdUnitInformation[Index].VerReg.Uint32 = MmioRead32 (mVtdUnitInformation[Index].VtdUnitBaseAddress + R_VER_REG);
  390. DumpVtdVerRegs (&mVtdUnitInformation[Index].VerReg);
  391. mVtdUnitInformation[Index].CapReg.Uint64 = MmioRead64 (mVtdUnitInformation[Index].VtdUnitBaseAddress + R_CAP_REG);
  392. DumpVtdCapRegs (&mVtdUnitInformation[Index].CapReg);
  393. mVtdUnitInformation[Index].ECapReg.Uint64 = MmioRead64 (mVtdUnitInformation[Index].VtdUnitBaseAddress + R_ECAP_REG);
  394. DumpVtdECapRegs (&mVtdUnitInformation[Index].ECapReg);
  395. if ((mVtdUnitInformation[Index].CapReg.Bits.SLLPS & BIT0) == 0) {
  396. DEBUG((DEBUG_WARN, "!!!! 2MB super page is not supported on VTD %d !!!!\n", Index));
  397. }
  398. if ((mVtdUnitInformation[Index].CapReg.Bits.SAGAW & BIT3) != 0) {
  399. DEBUG((DEBUG_INFO, "Support 5-level page-table on VTD %d\n", Index));
  400. }
  401. if ((mVtdUnitInformation[Index].CapReg.Bits.SAGAW & BIT2) != 0) {
  402. DEBUG((DEBUG_INFO, "Support 4-level page-table on VTD %d\n", Index));
  403. }
  404. if ((mVtdUnitInformation[Index].CapReg.Bits.SAGAW & (BIT3 | BIT2)) == 0) {
  405. DEBUG((DEBUG_ERROR, "!!!! Page-table type 0x%X is not supported on VTD %d !!!!\n", Index, mVtdUnitInformation[Index].CapReg.Bits.SAGAW));
  406. return ;
  407. }
  408. DomainNumber = (UINTN)1 << (UINT8)((UINTN)mVtdUnitInformation[Index].CapReg.Bits.ND * 2 + 4);
  409. if (mVtdUnitInformation[Index].PciDeviceInfo.PciDeviceDataNumber >= DomainNumber) {
  410. DEBUG((DEBUG_ERROR, "!!!! Pci device Number(0x%x) >= DomainNumber(0x%x) !!!!\n", mVtdUnitInformation[Index].PciDeviceInfo.PciDeviceDataNumber, DomainNumber));
  411. return ;
  412. }
  413. Status = PerpareCacheInvalidationInterface(Index);
  414. if (EFI_ERROR (Status)) {
  415. ASSERT(FALSE);
  416. return;
  417. }
  418. }
  419. return ;
  420. }
  421. /**
  422. Disable PMR in all VTd engine.
  423. **/
  424. VOID
  425. DisablePmr (
  426. VOID
  427. )
  428. {
  429. UINT32 Reg32;
  430. VTD_CAP_REG CapReg;
  431. UINTN Index;
  432. DEBUG ((DEBUG_INFO,"DisablePmr\n"));
  433. for (Index = 0; Index < mVtdUnitNumber; Index++) {
  434. CapReg.Uint64 = MmioRead64 (mVtdUnitInformation[Index].VtdUnitBaseAddress + R_CAP_REG);
  435. if (CapReg.Bits.PLMR == 0 || CapReg.Bits.PHMR == 0) {
  436. continue ;
  437. }
  438. Reg32 = MmioRead32 (mVtdUnitInformation[Index].VtdUnitBaseAddress + R_PMEN_ENABLE_REG);
  439. if ((Reg32 & BIT0) != 0) {
  440. MmioWrite32 (mVtdUnitInformation[Index].VtdUnitBaseAddress + R_PMEN_ENABLE_REG, 0x0);
  441. do {
  442. Reg32 = MmioRead32 (mVtdUnitInformation[Index].VtdUnitBaseAddress + R_PMEN_ENABLE_REG);
  443. } while((Reg32 & BIT0) != 0);
  444. DEBUG ((DEBUG_INFO,"Pmr(%d) disabled\n", Index));
  445. } else {
  446. DEBUG ((DEBUG_INFO,"Pmr(%d) not enabled\n", Index));
  447. }
  448. }
  449. return ;
  450. }
  451. /**
  452. Clear Global Command Register Bits
  453. @param[in] VtdUnitBaseAddress The base address of the VTd engine.
  454. @param[in] BitMask Bit mask.
  455. **/
  456. VOID
  457. ClearGlobalCommandRegisterBits (
  458. IN UINTN VtdUnitBaseAddress,
  459. IN UINT32 BitMask
  460. )
  461. {
  462. UINT32 Reg32;
  463. UINT32 Status;
  464. UINT32 Command;
  465. Reg32 = MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG);
  466. Status = (Reg32 & 0x96FFFFFF); // Reset the one-shot bits
  467. Command = (Status & (~BitMask));
  468. MmioWrite32 (VtdUnitBaseAddress + R_GCMD_REG, Command);
  469. DEBUG((DEBUG_INFO, "Clear GCMD_REG bits 0x%x.\n", BitMask));
  470. //
  471. // Poll on Status bit of Global status register to become zero
  472. //
  473. do {
  474. Reg32 = MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG);
  475. } while ((Reg32 & BitMask) == BitMask);
  476. DEBUG ((DEBUG_INFO, "GSTS_REG : 0x%08x \n", Reg32));
  477. }
  478. /**
  479. Set Global Command Register Bits
  480. @param[in] VtdUnitBaseAddress The base address of the VTd engine.
  481. @param[in] BitMask Bit mask.
  482. **/
  483. VOID
  484. SetGlobalCommandRegisterBits (
  485. IN UINTN VtdUnitBaseAddress,
  486. IN UINT32 BitMask
  487. )
  488. {
  489. UINT32 Reg32;
  490. UINT32 Status;
  491. UINT32 Command;
  492. Reg32 = MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG);
  493. Status = (Reg32 & 0x96FFFFFF); // Reset the one-shot bits
  494. Command = (Status | BitMask);
  495. MmioWrite32 (VtdUnitBaseAddress + R_GCMD_REG, Command);
  496. DEBUG((DEBUG_INFO, "Set GCMD_REG bits 0x%x.\n", BitMask));
  497. //
  498. // Poll on Status bit of Global status register to become not zero
  499. //
  500. do {
  501. Reg32 = MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG);
  502. } while ((Reg32 & BitMask) == 0);
  503. DEBUG ((DEBUG_INFO, "GSTS_REG : 0x%08x \n", Reg32));
  504. }
  505. /**
  506. Update Root Table Address Register
  507. @param[in] VtdIndex The index used to identify a VTd engine.
  508. @param[in] EnableADM TRUE - Enable ADM in TTM bits
  509. **/
  510. VOID
  511. UpdateRootTableAddressRegister (
  512. IN UINTN VtdIndex,
  513. IN BOOLEAN EnableADM
  514. )
  515. {
  516. UINT64 Reg64;
  517. if (mVtdUnitInformation[VtdIndex].ExtRootEntryTable != NULL) {
  518. DEBUG((DEBUG_INFO, "ExtRootEntryTable 0x%x \n", mVtdUnitInformation[VtdIndex].ExtRootEntryTable));
  519. Reg64 = (UINT64)(UINTN)mVtdUnitInformation[VtdIndex].ExtRootEntryTable | (EnableADM ? V_RTADDR_REG_TTM_ADM : BIT11);
  520. } else {
  521. DEBUG((DEBUG_INFO, "RootEntryTable 0x%x \n", mVtdUnitInformation[VtdIndex].RootEntryTable));
  522. Reg64 = (UINT64)(UINTN)mVtdUnitInformation[VtdIndex].RootEntryTable | (EnableADM ? V_RTADDR_REG_TTM_ADM : 0);
  523. }
  524. MmioWrite64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_RTADDR_REG, Reg64);
  525. }
  526. /**
  527. Enable DMAR translation.
  528. @retval EFI_SUCCESS DMAR translation is enabled.
  529. @retval EFI_DEVICE_ERROR DMAR translation is not enabled.
  530. **/
  531. EFI_STATUS
  532. EnableDmar (
  533. VOID
  534. )
  535. {
  536. UINTN Index;
  537. UINTN VtdUnitBaseAddress;
  538. BOOLEAN TEWasEnabled;
  539. for (Index = 0; Index < mVtdUnitNumber; Index++) {
  540. VtdUnitBaseAddress = mVtdUnitInformation[Index].VtdUnitBaseAddress;
  541. DEBUG((DEBUG_INFO, ">>>>>>EnableDmar() for engine [%d] BAR [0x%x]\n", Index, VtdUnitBaseAddress));
  542. //
  543. // Check TE was enabled or not.
  544. //
  545. TEWasEnabled = ((MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG) & B_GSTS_REG_TE) == B_GSTS_REG_TE);
  546. if (TEWasEnabled && (mVtdUnitInformation[Index].ECapReg.Bits.ADMS == 1) && PcdGetBool (PcdVTdSupportAbortDmaMode)) {
  547. //
  548. // For implementations reporting Enhanced SRTP Support (ESRTPS) field as
  549. // Clear in the Capability register, software must not modify this field while
  550. // DMA remapping is active (TES=1 in Global Status register).
  551. //
  552. if (mVtdUnitInformation[Index].CapReg.Bits.ESRTPS == 0) {
  553. ClearGlobalCommandRegisterBits (VtdUnitBaseAddress, B_GMCD_REG_TE);
  554. }
  555. //
  556. // Enable ADM
  557. //
  558. UpdateRootTableAddressRegister (Index, TRUE);
  559. DEBUG((DEBUG_INFO, "EnableDmar: waiting for RTPS bit to be set... \n"));
  560. SetGlobalCommandRegisterBits (VtdUnitBaseAddress, B_GMCD_REG_SRTP);
  561. DEBUG((DEBUG_INFO, "Enable Abort DMA Mode...\n"));
  562. SetGlobalCommandRegisterBits (VtdUnitBaseAddress, B_GMCD_REG_TE);
  563. } else {
  564. UpdateRootTableAddressRegister (Index, FALSE);
  565. DEBUG((DEBUG_INFO, "EnableDmar: waiting for RTPS bit to be set... \n"));
  566. SetGlobalCommandRegisterBits (VtdUnitBaseAddress, B_GMCD_REG_SRTP);
  567. }
  568. //
  569. // Write Buffer Flush before invalidation
  570. //
  571. FlushWriteBuffer (Index);
  572. //
  573. // Invalidate the context cache
  574. //
  575. InvalidateContextCache (Index);
  576. //
  577. // Invalidate the IOTLB cache
  578. //
  579. InvalidateIOTLB (Index);
  580. if (TEWasEnabled && (mVtdUnitInformation[Index].ECapReg.Bits.ADMS == 1) && PcdGetBool (PcdVTdSupportAbortDmaMode)) {
  581. if (mVtdUnitInformation[Index].CapReg.Bits.ESRTPS == 0) {
  582. ClearGlobalCommandRegisterBits (VtdUnitBaseAddress, B_GMCD_REG_TE);
  583. }
  584. UpdateRootTableAddressRegister (Index, FALSE);
  585. DEBUG((DEBUG_INFO, "EnableDmar: waiting for RTPS bit to be set... \n"));
  586. SetGlobalCommandRegisterBits (VtdUnitBaseAddress, B_GMCD_REG_SRTP);
  587. }
  588. //
  589. // Enable VTd
  590. //
  591. DEBUG ((DEBUG_INFO, "EnableDmar: Waiting B_GSTS_REG_TE ...\n"));
  592. SetGlobalCommandRegisterBits (VtdUnitBaseAddress, B_GMCD_REG_TE);
  593. DEBUG ((DEBUG_INFO,"VTD (%d) enabled!<<<<<<\n",Index));
  594. }
  595. //
  596. // Need disable PMR, since we already setup translation table.
  597. //
  598. DisablePmr ();
  599. mVtdEnabled = TRUE;
  600. return EFI_SUCCESS;
  601. }
  602. /**
  603. Disable DMAR translation.
  604. @retval EFI_SUCCESS DMAR translation is disabled.
  605. @retval EFI_DEVICE_ERROR DMAR translation is not disabled.
  606. **/
  607. EFI_STATUS
  608. DisableDmar (
  609. VOID
  610. )
  611. {
  612. UINTN Index;
  613. UINTN SubIndex;
  614. UINT32 Reg32;
  615. for (Index = 0; Index < mVtdUnitNumber; Index++) {
  616. DEBUG((DEBUG_INFO, ">>>>>>DisableDmar() for engine [%d] \n", Index));
  617. //
  618. // Write Buffer Flush before invalidation
  619. //
  620. FlushWriteBuffer (Index);
  621. //
  622. // Disable Dmar
  623. //
  624. //
  625. // Set TE (Translation Enable: BIT31) of Global command register to zero
  626. //
  627. ClearGlobalCommandRegisterBits (mVtdUnitInformation[Index].VtdUnitBaseAddress, B_GMCD_REG_TE);
  628. //
  629. // Set SRTP (Set Root Table Pointer: BIT30) of Global command register in order to update the root table pointerDisable VTd
  630. //
  631. SetGlobalCommandRegisterBits (mVtdUnitInformation[Index].VtdUnitBaseAddress, B_GSTS_REG_RTPS);
  632. Reg32 = MmioRead32 (mVtdUnitInformation[Index].VtdUnitBaseAddress + R_GSTS_REG);
  633. DEBUG ((DEBUG_INFO, "DisableDmar: GSTS_REG - 0x%08x\n", Reg32));
  634. DEBUG ((DEBUG_INFO,"VTD (%d) Disabled!<<<<<<\n",Index));
  635. DisableQueuedInvalidationInterface(Index);
  636. }
  637. mVtdEnabled = FALSE;
  638. for (Index = 0; Index < mVtdUnitNumber; Index++) {
  639. DEBUG((DEBUG_INFO, "engine [%d] access\n", Index));
  640. for (SubIndex = 0; SubIndex < mVtdUnitInformation[Index].PciDeviceInfo.PciDeviceDataNumber; SubIndex++) {
  641. DEBUG ((DEBUG_INFO, " PCI S%04X B%02x D%02x F%02x - %d\n",
  642. mVtdUnitInformation[Index].Segment,
  643. mVtdUnitInformation[Index].PciDeviceInfo.PciDeviceData[Index].PciSourceId.Bits.Bus,
  644. mVtdUnitInformation[Index].PciDeviceInfo.PciDeviceData[Index].PciSourceId.Bits.Device,
  645. mVtdUnitInformation[Index].PciDeviceInfo.PciDeviceData[Index].PciSourceId.Bits.Function,
  646. mVtdUnitInformation[Index].PciDeviceInfo.PciDeviceData[Index].AccessCount
  647. ));
  648. }
  649. }
  650. return EFI_SUCCESS;
  651. }
  652. /**
  653. Dump VTd version registers.
  654. @param[in] VerReg The version register.
  655. **/
  656. VOID
  657. DumpVtdVerRegs (
  658. IN VTD_VER_REG *VerReg
  659. )
  660. {
  661. DEBUG ((DEBUG_INFO, " VerReg - 0x%x\n", VerReg->Uint32));
  662. DEBUG ((DEBUG_INFO, " Major - 0x%x\n", VerReg->Bits.Major));
  663. DEBUG ((DEBUG_INFO, " Minor - 0x%x\n", VerReg->Bits.Minor));
  664. }
  665. /**
  666. Dump VTd capability registers.
  667. @param[in] CapReg The capability register.
  668. **/
  669. VOID
  670. DumpVtdCapRegs (
  671. IN VTD_CAP_REG *CapReg
  672. )
  673. {
  674. DEBUG((DEBUG_INFO, " CapReg - 0x%x\n", CapReg->Uint64));
  675. DEBUG((DEBUG_INFO, " ND - 0x%x\n", CapReg->Bits.ND));
  676. DEBUG((DEBUG_INFO, " AFL - 0x%x\n", CapReg->Bits.AFL));
  677. DEBUG((DEBUG_INFO, " RWBF - 0x%x\n", CapReg->Bits.RWBF));
  678. DEBUG((DEBUG_INFO, " PLMR - 0x%x\n", CapReg->Bits.PLMR));
  679. DEBUG((DEBUG_INFO, " PHMR - 0x%x\n", CapReg->Bits.PHMR));
  680. DEBUG((DEBUG_INFO, " CM - 0x%x\n", CapReg->Bits.CM));
  681. DEBUG((DEBUG_INFO, " SAGAW - 0x%x\n", CapReg->Bits.SAGAW));
  682. DEBUG((DEBUG_INFO, " MGAW - 0x%x\n", CapReg->Bits.MGAW));
  683. DEBUG((DEBUG_INFO, " ZLR - 0x%x\n", CapReg->Bits.ZLR));
  684. DEBUG((DEBUG_INFO, " FRO - 0x%x\n", CapReg->Bits.FRO));
  685. DEBUG((DEBUG_INFO, " SLLPS - 0x%x\n", CapReg->Bits.SLLPS));
  686. DEBUG((DEBUG_INFO, " PSI - 0x%x\n", CapReg->Bits.PSI));
  687. DEBUG((DEBUG_INFO, " NFR - 0x%x\n", CapReg->Bits.NFR));
  688. DEBUG((DEBUG_INFO, " MAMV - 0x%x\n", CapReg->Bits.MAMV));
  689. DEBUG((DEBUG_INFO, " DWD - 0x%x\n", CapReg->Bits.DWD));
  690. DEBUG((DEBUG_INFO, " DRD - 0x%x\n", CapReg->Bits.DRD));
  691. DEBUG((DEBUG_INFO, " FL1GP - 0x%x\n", CapReg->Bits.FL1GP));
  692. DEBUG((DEBUG_INFO, " PI - 0x%x\n", CapReg->Bits.PI));
  693. }
  694. /**
  695. Dump VTd extended capability registers.
  696. @param[in] ECapReg The extended capability register.
  697. **/
  698. VOID
  699. DumpVtdECapRegs (
  700. IN VTD_ECAP_REG *ECapReg
  701. )
  702. {
  703. DEBUG((DEBUG_INFO, " ECapReg - 0x%x\n", ECapReg->Uint64));
  704. DEBUG((DEBUG_INFO, " C - 0x%x\n", ECapReg->Bits.C));
  705. DEBUG((DEBUG_INFO, " QI - 0x%x\n", ECapReg->Bits.QI));
  706. DEBUG((DEBUG_INFO, " DT - 0x%x\n", ECapReg->Bits.DT));
  707. DEBUG((DEBUG_INFO, " IR - 0x%x\n", ECapReg->Bits.IR));
  708. DEBUG((DEBUG_INFO, " EIM - 0x%x\n", ECapReg->Bits.EIM));
  709. DEBUG((DEBUG_INFO, " PT - 0x%x\n", ECapReg->Bits.PT));
  710. DEBUG((DEBUG_INFO, " SC - 0x%x\n", ECapReg->Bits.SC));
  711. DEBUG((DEBUG_INFO, " IRO - 0x%x\n", ECapReg->Bits.IRO));
  712. DEBUG((DEBUG_INFO, " MHMV - 0x%x\n", ECapReg->Bits.MHMV));
  713. DEBUG((DEBUG_INFO, " MTS - 0x%x\n", ECapReg->Bits.MTS));
  714. DEBUG((DEBUG_INFO, " NEST - 0x%x\n", ECapReg->Bits.NEST));
  715. DEBUG((DEBUG_INFO, " PASID - 0x%x\n", ECapReg->Bits.PASID));
  716. DEBUG((DEBUG_INFO, " PRS - 0x%x\n", ECapReg->Bits.PRS));
  717. DEBUG((DEBUG_INFO, " ERS - 0x%x\n", ECapReg->Bits.ERS));
  718. DEBUG((DEBUG_INFO, " SRS - 0x%x\n", ECapReg->Bits.SRS));
  719. DEBUG((DEBUG_INFO, " NWFS - 0x%x\n", ECapReg->Bits.NWFS));
  720. DEBUG((DEBUG_INFO, " EAFS - 0x%x\n", ECapReg->Bits.EAFS));
  721. DEBUG((DEBUG_INFO, " PSS - 0x%x\n", ECapReg->Bits.PSS));
  722. DEBUG((DEBUG_INFO, " SMTS - 0x%x\n", ECapReg->Bits.SMTS));
  723. DEBUG((DEBUG_INFO, " ADMS - 0x%x\n", ECapReg->Bits.ADMS));
  724. }
  725. /**
  726. Dump VTd registers.
  727. @param[in] VtdIndex The index of VTd engine.
  728. **/
  729. VOID
  730. DumpVtdRegs (
  731. IN UINTN VtdIndex
  732. )
  733. {
  734. UINTN Index;
  735. UINT64 Reg64;
  736. VTD_FRCD_REG FrcdReg;
  737. VTD_CAP_REG CapReg;
  738. UINT32 Reg32;
  739. VTD_SOURCE_ID SourceId;
  740. DEBUG((DEBUG_INFO, "#### DumpVtdRegs(%d) Begin ####\n", VtdIndex));
  741. Reg32 = MmioRead32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_VER_REG);
  742. DEBUG((DEBUG_INFO, " VER_REG - 0x%08x\n", Reg32));
  743. CapReg.Uint64 = MmioRead64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_CAP_REG);
  744. DEBUG((DEBUG_INFO, " CAP_REG - 0x%016lx\n", CapReg.Uint64));
  745. Reg64 = MmioRead64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_ECAP_REG);
  746. DEBUG((DEBUG_INFO, " ECAP_REG - 0x%016lx\n", Reg64));
  747. Reg32 = MmioRead32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_GSTS_REG);
  748. DEBUG((DEBUG_INFO, " GSTS_REG - 0x%08x \n", Reg32));
  749. Reg64 = MmioRead64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_RTADDR_REG);
  750. DEBUG((DEBUG_INFO, " RTADDR_REG - 0x%016lx\n", Reg64));
  751. Reg64 = MmioRead64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_CCMD_REG);
  752. DEBUG((DEBUG_INFO, " CCMD_REG - 0x%016lx\n", Reg64));
  753. Reg32 = MmioRead32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_FSTS_REG);
  754. DEBUG((DEBUG_INFO, " FSTS_REG - 0x%08x\n", Reg32));
  755. Reg32 = MmioRead32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_FECTL_REG);
  756. DEBUG((DEBUG_INFO, " FECTL_REG - 0x%08x\n", Reg32));
  757. Reg32 = MmioRead32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_FEDATA_REG);
  758. DEBUG((DEBUG_INFO, " FEDATA_REG - 0x%08x\n", Reg32));
  759. Reg32 = MmioRead32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_FEADDR_REG);
  760. DEBUG((DEBUG_INFO, " FEADDR_REG - 0x%08x\n",Reg32));
  761. Reg32 = MmioRead32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_FEUADDR_REG);
  762. DEBUG((DEBUG_INFO, " FEUADDR_REG - 0x%08x\n",Reg32));
  763. for (Index = 0; Index < (UINTN)CapReg.Bits.NFR + 1; Index++) {
  764. FrcdReg.Uint64[0] = MmioRead64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + ((CapReg.Bits.FRO * 16) + (Index * 16) + R_FRCD_REG));
  765. FrcdReg.Uint64[1] = MmioRead64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + ((CapReg.Bits.FRO * 16) + (Index * 16) + R_FRCD_REG + sizeof(UINT64)));
  766. DEBUG((DEBUG_INFO, " FRCD_REG[%d] - 0x%016lx %016lx\n", Index, FrcdReg.Uint64[1], FrcdReg.Uint64[0]));
  767. if (FrcdReg.Uint64[1] != 0 || FrcdReg.Uint64[0] != 0) {
  768. DEBUG((DEBUG_INFO, " Fault Info - 0x%016lx\n", VTD_64BITS_ADDRESS(FrcdReg.Bits.FILo, FrcdReg.Bits.FIHi)));
  769. DEBUG((DEBUG_INFO, " Fault Bit - %d\n", FrcdReg.Bits.F));
  770. SourceId.Uint16 = (UINT16)FrcdReg.Bits.SID;
  771. DEBUG((DEBUG_INFO, " Source - B%02x D%02x F%02x\n", SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function));
  772. DEBUG((DEBUG_INFO, " Type - 0x%02x\n", (FrcdReg.Bits.T1 << 1) | FrcdReg.Bits.T2));
  773. DEBUG((DEBUG_INFO, " Reason - %x (Refer to VTd Spec, Appendix A)\n", FrcdReg.Bits.FR));
  774. }
  775. }
  776. Reg64 = MmioRead64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + (mVtdUnitInformation[VtdIndex].ECapReg.Bits.IRO * 16) + R_IVA_REG);
  777. DEBUG((DEBUG_INFO, " IVA_REG - 0x%016lx\n",Reg64));
  778. Reg64 = MmioRead64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + (mVtdUnitInformation[VtdIndex].ECapReg.Bits.IRO * 16) + R_IOTLB_REG);
  779. DEBUG((DEBUG_INFO, " IOTLB_REG - 0x%016lx\n",Reg64));
  780. DEBUG((DEBUG_INFO, "#### DumpVtdRegs(%d) End ####\n", VtdIndex));
  781. }
  782. /**
  783. Dump VTd registers for all VTd engine.
  784. **/
  785. VOID
  786. DumpVtdRegsAll (
  787. VOID
  788. )
  789. {
  790. UINTN Num;
  791. for (Num = 0; Num < mVtdUnitNumber; Num++) {
  792. DumpVtdRegs (Num);
  793. }
  794. }
  795. /**
  796. Dump VTd registers if there is error.
  797. **/
  798. VOID
  799. DumpVtdIfError (
  800. VOID
  801. )
  802. {
  803. UINTN Num;
  804. UINTN Index;
  805. VTD_FRCD_REG FrcdReg;
  806. VTD_CAP_REG CapReg;
  807. UINT32 Reg32;
  808. BOOLEAN HasError;
  809. for (Num = 0; Num < mVtdUnitNumber; Num++) {
  810. HasError = FALSE;
  811. Reg32 = MmioRead32 (mVtdUnitInformation[Num].VtdUnitBaseAddress + R_FSTS_REG);
  812. if (Reg32 != 0) {
  813. HasError = TRUE;
  814. }
  815. Reg32 = MmioRead32 (mVtdUnitInformation[Num].VtdUnitBaseAddress + R_FECTL_REG);
  816. if ((Reg32 & BIT30) != 0) {
  817. HasError = TRUE;
  818. }
  819. CapReg.Uint64 = MmioRead64 (mVtdUnitInformation[Num].VtdUnitBaseAddress + R_CAP_REG);
  820. for (Index = 0; Index < (UINTN)CapReg.Bits.NFR + 1; Index++) {
  821. FrcdReg.Uint64[0] = MmioRead64 (mVtdUnitInformation[Num].VtdUnitBaseAddress + ((CapReg.Bits.FRO * 16) + (Index * 16) + R_FRCD_REG));
  822. FrcdReg.Uint64[1] = MmioRead64 (mVtdUnitInformation[Num].VtdUnitBaseAddress + ((CapReg.Bits.FRO * 16) + (Index * 16) + R_FRCD_REG + sizeof(UINT64)));
  823. if (FrcdReg.Bits.F != 0) {
  824. HasError = TRUE;
  825. }
  826. }
  827. if (HasError) {
  828. REPORT_STATUS_CODE (EFI_ERROR_CODE, PcdGet32 (PcdErrorCodeVTdError));
  829. DEBUG((DEBUG_INFO, "\n#### ERROR ####\n"));
  830. DumpVtdRegs (Num);
  831. DEBUG((DEBUG_INFO, "#### ERROR ####\n\n"));
  832. //
  833. // Clear
  834. //
  835. for (Index = 0; Index < (UINTN)CapReg.Bits.NFR + 1; Index++) {
  836. FrcdReg.Uint64[1] = MmioRead64 (mVtdUnitInformation[Num].VtdUnitBaseAddress + ((CapReg.Bits.FRO * 16) + (Index * 16) + R_FRCD_REG + sizeof(UINT64)));
  837. if (FrcdReg.Bits.F != 0) {
  838. //
  839. // Software writes the value read from this field (F) to Clear it.
  840. //
  841. MmioWrite64 (mVtdUnitInformation[Num].VtdUnitBaseAddress + ((CapReg.Bits.FRO * 16) + (Index * 16) + R_FRCD_REG + sizeof(UINT64)), FrcdReg.Uint64[1]);
  842. }
  843. }
  844. MmioWrite32 (mVtdUnitInformation[Num].VtdUnitBaseAddress + R_FSTS_REG, MmioRead32 (mVtdUnitInformation[Num].VtdUnitBaseAddress + R_FSTS_REG));
  845. }
  846. }
  847. }