public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: Laszlo Ersek <lersek@redhat.com>
To: edk2-devel-01 <edk2-devel@ml01.01.org>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Subject: [PATCH 5/5] OvmfPkg/QemuFwCfgLib: support QEMU's DMA-like fw_cfg access method
Date: Thu,  1 Dec 2016 18:56:33 +0100	[thread overview]
Message-ID: <20161201175633.2538-6-lersek@redhat.com> (raw)
In-Reply-To: <20161201175633.2538-1-lersek@redhat.com>

The benefits of the DMA-like access method are (a) speed, (b) write
support in QEMU 2.9+.

(IOPort-based write support was discontinued in QEMU 2.4, and the
DMA-based one is being added to QEMU 2.9. Write support needs no separate
feature detection because writeability is governed on the level of
individual fw_cfg files -- if a file meant to be written by the firmware
exists in the directory, then it is writeable with the DMA method.)

We don't enable this feature for the SEC library instance, because:
- the SEC instance remains without clients (I've checked that it builds
  though),
- in SEC, any possible fw_cfg use is expected to be small and read-only.

Cc: Jordan Justen <jordan.l.justen@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
---
 OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgLibInternal.h | 13 ++++
 OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgLib.c         | 73 ++++++++++++++++++++
 OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgPeiDxe.c      | 26 ++++++-
 OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgSec.c         | 15 ++++
 4 files changed, 126 insertions(+), 1 deletion(-)

diff --git a/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgLibInternal.h b/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgLibInternal.h
index 5b162bf98739..6e87c625102e 100644
--- a/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgLibInternal.h
+++ b/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgLibInternal.h
@@ -30,4 +30,17 @@ InternalQemuFwCfgIsAvailable (
   VOID
   );
 
+
+/**
+  Returns a boolean indicating whether QEMU provides the DMA-like access method
+  for fw_cfg.
+
+  @retval    TRUE   The DMA-like access method is available.
+  @retval    FALSE  The DMA-like access method is unavailable.
+**/
+BOOLEAN
+InternalQemuFwCfgDmaIsAvailable (
+  VOID
+  );
+
 #endif
diff --git a/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgLib.c b/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgLib.c
index 804d5b0e42be..f609f6422878 100644
--- a/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgLib.c
+++ b/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgLib.c
@@ -21,6 +21,7 @@
 #include <Library/QemuFwCfgLib.h>
 #include <Library/MemoryAllocationLib.h>
 #include <Library/UefiBootServicesTableLib.h>
+#include <IndustryStandard/QemuFwCfgDma.h>
 
 #include "QemuFwCfgLibInternal.h"
 
@@ -99,6 +100,70 @@ QemuFwCfgSelectItem (
 
 
 /**
+  Transfer an array of bytes using the DMA interface.
+
+  @param[in]     Size    Size in bytes to transfer.
+  @param[in,out] Buffer  Buffer to read data into or write data from. May be
+                         NULL if Size is zero.
+  @param[in]     Write   TRUE if writing to fw_cfg from Buffer, FALSE if
+                         reading from fw_cfg into Buffer.
+**/
+VOID
+InternalQemuFwCfgDmaBytes (
+  IN     UINT32   Size,
+  IN OUT VOID     *Buffer OPTIONAL,
+  IN     BOOLEAN  Write
+  )
+{
+  volatile FW_CFG_DMA_ACCESS Access;
+  UINT32                     AccessHigh, AccessLow;
+  UINT32                     Status;
+
+  if (Size == 0) {
+    return;
+  }
+
+  Access.Control = SwapBytes32 (
+                    Write ? FW_CFG_DMA_CTL_WRITE : FW_CFG_DMA_CTL_READ
+                    );
+  Access.Length  = SwapBytes32 (Size);
+  Access.Address = SwapBytes64 ((UINTN)Buffer);
+
+  //
+  // Delimit the transfer from (a) modifications to Access, (b) in case of a
+  // write, from writes to Buffer by the caller.
+  //
+  MemoryFence ();
+
+  //
+  // Start the transfer.
+  //
+  AccessHigh = (UINT32)RShiftU64 ((UINTN)&Access, 32);
+  AccessLow  = (UINT32)(UINTN)&Access;
+  IoWrite32 (0x514, SwapBytes32 (AccessHigh));
+  IoWrite32 (0x518, SwapBytes32 (AccessLow));
+
+  //
+  // Don't look at Access.Control before starting the transfer.
+  //
+  MemoryFence ();
+
+  //
+  // Wait for the transfer to complete.
+  //
+  do {
+    Status = SwapBytes32 (Access.Control);
+    ASSERT ((Status & FW_CFG_DMA_CTL_ERROR) == 0);
+  } while (Status != 0);
+
+  //
+  // After a read, the caller will want to use Buffer.
+  //
+  MemoryFence ();
+}
+
+
+/**
   Reads firmware configuration bytes into a buffer
 
   @param[in] Size - Size in bytes to read
@@ -112,6 +177,10 @@ InternalQemuFwCfgReadBytes (
   IN VOID                   *Buffer  OPTIONAL
   )
 {
+  if (InternalQemuFwCfgDmaIsAvailable () && Size <= MAX_UINT32) {
+    InternalQemuFwCfgDmaBytes ((UINT32)Size, Buffer, FALSE);
+    return;
+  }
   IoReadFifo8 (0x511, Size, Buffer);
 }
 
@@ -160,6 +229,10 @@ QemuFwCfgWriteBytes (
   )
 {
   if (InternalQemuFwCfgIsAvailable ()) {
+    if (InternalQemuFwCfgDmaIsAvailable () && Size <= MAX_UINT32) {
+      InternalQemuFwCfgDmaBytes ((UINT32)Size, Buffer, TRUE);
+      return;
+    }
     IoWriteFifo8 (0x511, Size, Buffer);
   }
 }
diff --git a/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgPeiDxe.c b/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgPeiDxe.c
index 88d88c0edf69..fde4a11b4e0d 100644
--- a/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgPeiDxe.c
+++ b/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgPeiDxe.c
@@ -14,12 +14,14 @@
   WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 **/
 
+#include <IndustryStandard/QemuFwCfgDma.h>
 #include <Library/DebugLib.h>
 #include <Library/QemuFwCfgLib.h>
 
 #include "QemuFwCfgLibInternal.h"
 
 STATIC BOOLEAN mQemuFwCfgSupported = FALSE;
+STATIC BOOLEAN mQemuFwCfgDmaSupported;
 
 
 /**
@@ -53,8 +55,10 @@ QemuFwCfgInitialize (
 
   //
   // Enable the access routines while probing to see if it is supported.
+  // For probing we always use the IO Port (IoReadFifo8()) access method.
   //
   mQemuFwCfgSupported = TRUE;
+  mQemuFwCfgDmaSupported = FALSE;
 
   QemuFwCfgSelectItem (QemuFwCfgItemSignature);
   Signature = QemuFwCfgRead32 ();
@@ -70,7 +74,12 @@ QemuFwCfgInitialize (
     return RETURN_SUCCESS;
   }
 
-  DEBUG ((EFI_D_INFO, "QemuFwCfg interface is supported.\n"));
+  if ((Revision & FW_CFG_F_DMA) == 0) {
+    DEBUG ((DEBUG_INFO, "QemuFwCfg interface (IO Port) is supported.\n"));
+  } else {
+    mQemuFwCfgDmaSupported = TRUE;
+    DEBUG ((DEBUG_INFO, "QemuFwCfg interface (DMA) is supported.\n"));
+  }
   return RETURN_SUCCESS;
 }
 
@@ -91,3 +100,18 @@ InternalQemuFwCfgIsAvailable (
 {
   return mQemuFwCfgSupported;
 }
+
+/**
+  Returns a boolean indicating whether QEMU provides the DMA-like access method
+  for fw_cfg.
+
+  @retval    TRUE   The DMA-like access method is available.
+  @retval    FALSE  The DMA-like access method is unavailable.
+**/
+BOOLEAN
+InternalQemuFwCfgDmaIsAvailable (
+  VOID
+  )
+{
+  return mQemuFwCfgDmaSupported;
+}
diff --git a/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgSec.c b/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgSec.c
index 56c59ca3f01d..465ccbe90dad 100644
--- a/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgSec.c
+++ b/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgSec.c
@@ -79,3 +79,18 @@ InternalQemuFwCfgIsAvailable (
   //
   return TRUE;
 }
+
+/**
+  Returns a boolean indicating whether QEMU provides the DMA-like access method
+  for fw_cfg.
+
+  @retval    TRUE   The DMA-like access method is available.
+  @retval    FALSE  The DMA-like access method is unavailable.
+**/
+BOOLEAN
+InternalQemuFwCfgDmaIsAvailable (
+  VOID
+  )
+{
+  return FALSE;
+}
-- 
2.9.2



      parent reply	other threads:[~2016-12-01 17:56 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-12-01 17:56 [PATCH 0/5] OvmfPkg/QemuFwCfgLib: support the DMA-like interface Laszlo Ersek
2016-12-01 17:56 ` [PATCH 1/5] ArmVirtPkg/QemuFwCfgLib: remove superfluous InternalQemuFwCfgIsAvailable() Laszlo Ersek
2016-12-02 10:58   ` Leif Lindholm
2016-12-01 17:56 ` [PATCH 2/5] OvmfPkg/QemuFwCfgLib: move InternalQemuFwCfgIsAvailable() to lib instances Laszlo Ersek
2016-12-01 17:56 ` [PATCH 3/5] OvmfPkg/IndustryStandard: add QemuFwCfgDma.h Laszlo Ersek
2016-12-01 19:34   ` Jordan Justen
2016-12-01 20:48     ` Laszlo Ersek
2016-12-02  1:01       ` Jordan Justen
2016-12-02 10:05         ` Laszlo Ersek
2016-12-01 17:56 ` [PATCH 4/5] ArmVirtPkg/QemuFwCfgLib: rebase lib instance to OvmfPkg/IndustryStandard Laszlo Ersek
2016-12-02 11:03   ` Leif Lindholm
2016-12-02 11:35     ` Laszlo Ersek
2016-12-01 17:56 ` Laszlo Ersek [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-list from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20161201175633.2538-6-lersek@redhat.com \
    --to=devel@edk2.groups.io \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox