]> git.proxmox.com Git - mirror_edk2.git/commitdiff
ArmVirtPkg: QemuFwCfgLib: read bytes from fw-cfg with DMA when available
authorLaszlo Ersek <lersek@redhat.com>
Thu, 24 Sep 2015 21:40:41 +0000 (21:40 +0000)
committerlersek <lersek@Edk2>
Thu, 24 Sep 2015 21:40:41 +0000 (21:40 +0000)
The protocol is documented in "docs/specs/fw_cfg.txt" in the QEMU tree.

Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
Reviewed-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@18545 6f19259b-4bc3-4df7-8a09-765794883524

ArmVirtPkg/Library/QemuFwCfgLib/QemuFwCfgLib.c
ArmVirtPkg/Library/QemuFwCfgLib/QemuFwCfgLib.inf

index c62eee3be8c8de244b856eb46e0009fed9eba506..303dc520c6eb975078a13da9bcd4b6e6f9828f3a 100644 (file)
 \r
 #include <Library/BaseLib.h>\r
 #include <Library/BaseMemoryLib.h>\r
+#include <Library/DebugLib.h>\r
 #include <Library/IoLib.h>\r
 #include <Library/PcdLib.h>\r
 #include <Library/QemuFwCfgLib.h>\r
 \r
 STATIC UINTN mFwCfgSelectorAddress;\r
 STATIC UINTN mFwCfgDataAddress;\r
+STATIC UINTN mFwCfgDmaAddress;\r
+\r
+/**\r
+  Reads firmware configuration bytes into a buffer\r
+\r
+  @param[in] Size    Size in bytes to read\r
+  @param[in] Buffer  Buffer to store data into  (OPTIONAL if Size is 0)\r
+\r
+**/\r
+typedef\r
+VOID (EFIAPI READ_BYTES_FUNCTION) (\r
+  IN UINTN Size,\r
+  IN VOID  *Buffer OPTIONAL\r
+  );\r
+\r
+//\r
+// Forward declaration of the two implementations we have.\r
+//\r
+STATIC READ_BYTES_FUNCTION MmioReadBytes;\r
+STATIC READ_BYTES_FUNCTION DmaReadBytes;\r
+\r
+//\r
+// This points to the one we detect at runtime.\r
+//\r
+STATIC READ_BYTES_FUNCTION *InternalQemuFwCfgReadBytes = MmioReadBytes;\r
+\r
+//\r
+// Communication structure for DmaReadBytes(). All fields are encoded in big\r
+// endian.\r
+//\r
+#pragma pack (1)\r
+typedef struct {\r
+  UINT32 Control;\r
+  UINT32 Length;\r
+  UINT64 Address;\r
+} FW_CFG_DMA_ACCESS;\r
+#pragma pack ()\r
+\r
+//\r
+// Macros for the FW_CFG_DMA_ACCESS.Control bitmap (in native encoding).\r
+//\r
+#define FW_CFG_DMA_CTL_ERROR  BIT0\r
+#define FW_CFG_DMA_CTL_READ   BIT1\r
+#define FW_CFG_DMA_CTL_SKIP   BIT2\r
+#define FW_CFG_DMA_CTL_SELECT BIT3\r
 \r
 \r
 /**\r
@@ -77,7 +123,22 @@ QemuFwCfgInitialize (
 \r
     QemuFwCfgSelectItem (QemuFwCfgItemSignature);\r
     Signature = QemuFwCfgRead32 ();\r
-    if (Signature != SIGNATURE_32 ('Q', 'E', 'M', 'U')) {\r
+    if (Signature == SIGNATURE_32 ('Q', 'E', 'M', 'U')) {\r
+      //\r
+      // For DMA support, we require the DTB to advertise the register, and the\r
+      // feature bitmap (which we read without DMA) to confirm the feature.\r
+      //\r
+      if (PcdGet64 (PcdFwCfgDmaAddress) != 0) {\r
+        UINT32 Features;\r
+\r
+        QemuFwCfgSelectItem (QemuFwCfgItemInterfaceVersion);\r
+        Features = QemuFwCfgRead32 ();\r
+        if ((Features & BIT1) != 0) {\r
+          mFwCfgDmaAddress = PcdGet64 (PcdFwCfgDmaAddress);\r
+          InternalQemuFwCfgReadBytes = DmaReadBytes;\r
+        }\r
+      }\r
+    } else {\r
       mFwCfgSelectorAddress = 0;\r
       mFwCfgDataAddress     = 0;\r
     }\r
@@ -108,16 +169,12 @@ QemuFwCfgSelectItem (
 \r
 \r
 /**\r
-  Reads firmware configuration bytes into a buffer\r
-\r
-  @param[in] Size    Size in bytes to read\r
-  @param[in] Buffer  Buffer to store data into  (OPTIONAL if Size is 0)\r
-\r
+  Slow READ_BYTES_FUNCTION.\r
 **/\r
 STATIC\r
 VOID\r
 EFIAPI\r
-InternalQemuFwCfgReadBytes (\r
+MmioReadBytes (\r
   IN UINTN Size,\r
   IN VOID  *Buffer OPTIONAL\r
   )\r
@@ -162,6 +219,61 @@ InternalQemuFwCfgReadBytes (
 }\r
 \r
 \r
+/**\r
+  Fast READ_BYTES_FUNCTION.\r
+**/\r
+STATIC\r
+VOID\r
+EFIAPI\r
+DmaReadBytes (\r
+  IN UINTN Size,\r
+  IN VOID  *Buffer OPTIONAL\r
+  )\r
+{\r
+  volatile FW_CFG_DMA_ACCESS Access;\r
+  UINT32                     Status;\r
+\r
+  if (Size == 0) {\r
+    return;\r
+  }\r
+\r
+  ASSERT (Size <= MAX_UINT32);\r
+\r
+  Access.Control = SwapBytes32 (FW_CFG_DMA_CTL_READ);\r
+  Access.Length  = SwapBytes32 ((UINT32)Size);\r
+  Access.Address = SwapBytes64 ((UINT64)(UINTN)Buffer);\r
+\r
+  //\r
+  // We shouldn't start the transfer before setting up Access.\r
+  //\r
+  MemoryFence ();\r
+\r
+  //\r
+  // This will fire off the transfer.\r
+  //\r
+#ifdef MDE_CPU_AARCH64\r
+  MmioWrite64 (mFwCfgDmaAddress, SwapBytes64 ((UINT64)&Access));\r
+#else\r
+  MmioWrite32 ((UINT32)(mFwCfgDmaAddress + 4), SwapBytes32 ((UINT32)&Access));\r
+#endif\r
+\r
+  //\r
+  // We shouldn't look at Access.Control before starting the transfer.\r
+  //\r
+  MemoryFence ();\r
+\r
+  do {\r
+    Status = SwapBytes32 (Access.Control);\r
+    ASSERT ((Status & FW_CFG_DMA_CTL_ERROR) == 0);\r
+  } while (Status != 0);\r
+\r
+  //\r
+  // The caller will want to access the transferred data.\r
+  //\r
+  MemoryFence ();\r
+}\r
+\r
+\r
 /**\r
   Reads firmware configuration bytes into a buffer\r
 \r
index 42f21f20c02fffa06204e40ef0a3ced574e163da..298aa6edfb261cf4a2fdf384f54645531a9c32c4 100644 (file)
 [LibraryClasses]\r
   BaseLib\r
   BaseMemoryLib\r
+  DebugLib\r
   IoLib\r
   PcdLib\r
 \r
 [Pcd]\r
   gArmVirtTokenSpaceGuid.PcdFwCfgSelectorAddress\r
   gArmVirtTokenSpaceGuid.PcdFwCfgDataAddress\r
+  gArmVirtTokenSpaceGuid.PcdFwCfgDmaAddress\r