Update VirtioNetTransmit() to map the callers transmit buffer to a device
DMA address and use the DeviceAddress in vring descriptors.

Since the transmit buffers are returned back to caller in
VirtioNetGetStatus() hence we maintain a list to map DeviceAddress to
HostAddress. The list is consulted to find the correct HostAddress upon
transmit completion interruption.

Cc: Ard Biesheuvel <ard.biesheu...@linaro.org>
Cc: Jordan Justen <jordan.l.jus...@intel.com>
Cc: Tom Lendacky <thomas.lenda...@amd.com>
Cc: Laszlo Ersek <ler...@redhat.com>
Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Brijesh Singh <brijesh.si...@amd.com>
---
 OvmfPkg/VirtioNetDxe/VirtioNet.h        |  17 ++++
 OvmfPkg/VirtioNetDxe/SnpGetStatus.c     |  19 +++-
 OvmfPkg/VirtioNetDxe/SnpSharedHelpers.c | 100 ++++++++++++++++++++
 OvmfPkg/VirtioNetDxe/SnpTransmit.c      |  22 +++--
 4 files changed, 149 insertions(+), 9 deletions(-)

diff --git a/OvmfPkg/VirtioNetDxe/VirtioNet.h b/OvmfPkg/VirtioNetDxe/VirtioNet.h
index 873069e9de82..6c5129f178cd 100644
--- a/OvmfPkg/VirtioNetDxe/VirtioNet.h
+++ b/OvmfPkg/VirtioNetDxe/VirtioNet.h
@@ -269,6 +269,23 @@ VirtioNetShutdownTx (
   IN OUT VNET_DEV *Dev
   );
 
+EFI_STATUS
+EFIAPI
+VirtioMapTxBuf (
+  IN  VNET_DEV              *Dev,
+  IN  EFI_PHYSICAL_ADDRESS  HostAddress,
+  IN  UINTN                 NumberOfBytes,
+  OUT EFI_PHYSICAL_ADDRESS  *DeviceAddress
+  );
+
+EFI_STATUS
+EFIAPI
+VirtioUnmapTxBuf (
+  IN  VNET_DEV              *Dev,
+  OUT EFI_PHYSICAL_ADDRESS  *HostAddress,
+  IN  EFI_PHYSICAL_ADDRESS  DeviceAddress
+  );
+
 //
 // event callbacks
 //
diff --git a/OvmfPkg/VirtioNetDxe/SnpGetStatus.c 
b/OvmfPkg/VirtioNetDxe/SnpGetStatus.c
index 694940ea1d97..ddea29e65d57 100644
--- a/OvmfPkg/VirtioNetDxe/SnpGetStatus.c
+++ b/OvmfPkg/VirtioNetDxe/SnpGetStatus.c
@@ -5,6 +5,7 @@
 
   Copyright (C) 2013, Red Hat, Inc.
   Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+  Copyright (c) 2017, AMD Inc, All rights reserved.<BR>
 
   This program and the accompanying materials are licensed and made available
   under the terms and conditions of the BSD License which accompanies this
@@ -126,8 +127,10 @@ VirtioNetGetStatus (
       *TxBuf = NULL;
     }
     else {
-      UINT16 UsedElemIdx;
-      UINT32 DescIdx;
+      UINT16                UsedElemIdx;
+      UINT32                DescIdx;
+      EFI_PHYSICAL_ADDRESS  DeviceAddress;
+      EFI_PHYSICAL_ADDRESS  HostAddress;
 
       //
       // fetch the first descriptor among those that the hypervisor reports
@@ -141,9 +144,19 @@ VirtioNetGetStatus (
       ASSERT (DescIdx < (UINT32) (2 * Dev->TxMaxPending - 1));
 
       //
+      // Unmap the DeviceAddress
+      //
+      DeviceAddress = Dev->TxRing.Desc[DescIdx + 1].Addr;
+      Status = VirtioUnmapTxBuf (Dev, &HostAddress, DeviceAddress);
+      if (EFI_ERROR (Status)) {
+        goto Exit;
+      }
+
+      //
+      //
       // report buffer address to caller that has been enqueued by caller
       //
-      *TxBuf = (VOID *)(UINTN) Dev->TxRing.Desc[DescIdx + 1].Addr;
+      *TxBuf = (VOID *)(UINTN) HostAddress;
 
       //
       // now this descriptor can be used again to enqueue a transmit buffer
diff --git a/OvmfPkg/VirtioNetDxe/SnpSharedHelpers.c 
b/OvmfPkg/VirtioNetDxe/SnpSharedHelpers.c
index 3ed7132be531..6a6866e65b5f 100644
--- a/OvmfPkg/VirtioNetDxe/SnpSharedHelpers.c
+++ b/OvmfPkg/VirtioNetDxe/SnpSharedHelpers.c
@@ -14,10 +14,25 @@
 
 **/
 
+#include <Library/BaseLib.h>
 #include <Library/MemoryAllocationLib.h>
 
 #include "VirtioNet.h"
 
+#define PRIVATE_TXBUF_SIGNATURE  SIGNATURE_32 ('t', 'x', 'b', 'f')
+typedef struct {
+  UINT32                Signature;
+  LIST_ENTRY            Link;
+  EFI_PHYSICAL_ADDRESS  HostAddress;
+  EFI_PHYSICAL_ADDRESS  DeviceAddress;
+  VOID                  *Mapping;
+} PRIVATE_TXBUF_ENTRY;
+#define PRIVATE_TXBUF_FROM_LINK(a) CR (a, PRIVATE_TXBUF_ENTRY, Link, \
+                                       PRIVATE_TXBUF_SIGNATURE)
+
+STATIC LIST_ENTRY mTxBufMapList = INITIALIZE_LIST_HEAD_VARIABLE 
(mTxBufMapList);
+
+
 /**
   Release RX and TX resources on the boundary of the
   EfiSimpleNetworkInitialized state.
@@ -68,3 +83,88 @@ VirtioNetShutdownTx (
 
   FreePool (Dev->TxFreeStack);
 }
+
+EFI_STATUS
+EFIAPI
+VirtioMapTxBuf (
+  IN  VNET_DEV               *Dev,
+  IN  EFI_PHYSICAL_ADDRESS   HostAddress,
+  IN  UINTN                  NumberOfBytes,
+  OUT EFI_PHYSICAL_ADDRESS   *DeviceAddress
+  )
+{
+  EFI_STATUS             Status;
+  PRIVATE_TXBUF_ENTRY   *Private;
+
+  Private = AllocatePool (sizeof (*Private));
+  if (Private == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  Private->Signature = PRIVATE_TXBUF_SIGNATURE;
+  Private->HostAddress = HostAddress;
+
+  Status = VirtioMapSharedBufferRead (Dev->VirtIo,
+             (VOID *) (UINTN) Private->HostAddress, NumberOfBytes,
+             &Private->DeviceAddress, &Private->Mapping);
+  if (EFI_ERROR (Status)) {
+    FreePool (Private);
+    return Status;
+  }
+
+  *DeviceAddress = Private->DeviceAddress;
+
+  //
+  // Add the mapping information into internal list so that we can retrieve
+  // the HostAddress upon Unmap().
+  //
+  InsertTailList (&mTxBufMapList, &Private->Link);
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+VirtioUnmapTxBuf (
+  IN  VNET_DEV               *Dev,
+  OUT EFI_PHYSICAL_ADDRESS   *HostAddress,
+  IN  EFI_PHYSICAL_ADDRESS   DeviceAddress
+  )
+{
+  EFI_STATUS             Status;
+  PRIVATE_TXBUF_ENTRY   *Private;
+  LIST_ENTRY            *Link;
+  BOOLEAN                Found;
+
+  Found = FALSE;
+
+  //
+  // Iterate through internal txbuf list to find mapping for a given
+  // DeviceAddress.
+  //
+  for (Link = GetFirstNode (&mTxBufMapList)
+       ; !IsNull (&mTxBufMapList, Link)
+       ; Link = GetNextNode (&mTxBufMapList, Link)
+      ) {
+    Private = PRIVATE_TXBUF_FROM_LINK (Link);
+    if (Private->DeviceAddress == DeviceAddress) {
+      Found = TRUE;
+      break;
+    }
+  }
+
+  //
+  // We failed to find mapping for the given DeviceAddress
+  // (this should never happen)
+  //
+  ASSERT (Found);
+
+  Status = VirtioUnmapSharedBuffer (Dev->VirtIo, Private->Mapping);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  *HostAddress = Private->HostAddress;
+
+  return EFI_SUCCESS;
+}
diff --git a/OvmfPkg/VirtioNetDxe/SnpTransmit.c 
b/OvmfPkg/VirtioNetDxe/SnpTransmit.c
index 7ca40d5d0650..20c56c12df04 100644
--- a/OvmfPkg/VirtioNetDxe/SnpTransmit.c
+++ b/OvmfPkg/VirtioNetDxe/SnpTransmit.c
@@ -73,11 +73,12 @@ VirtioNetTransmit (
   IN UINT16                      *Protocol OPTIONAL
   )
 {
-  VNET_DEV   *Dev;
-  EFI_TPL    OldTpl;
-  EFI_STATUS Status;
-  UINT16     DescIdx;
-  UINT16     AvailIdx;
+  VNET_DEV              *Dev;
+  EFI_TPL               OldTpl;
+  EFI_STATUS            Status;
+  UINT16                DescIdx;
+  UINT16                AvailIdx;
+  EFI_PHYSICAL_ADDRESS  DeviceAddress;
 
   if (This == NULL || BufferSize == 0 || Buffer == NULL) {
     return EFI_INVALID_PARAMETER;
@@ -144,10 +145,19 @@ VirtioNetTransmit (
   }
 
   //
+  // Map the transmit buffer HostAddress to a DeviceAddress
+  //
+  Status = VirtioMapTxBuf (Dev, (EFI_PHYSICAL_ADDRESS) (UINTN) Buffer,
+             BufferSize, &DeviceAddress);
+  if (EFI_ERROR (Status)) {
+    goto Exit;
+  }
+
+  //
   // virtio-0.9.5, 2.4.1 Supplying Buffers to The Device
   //
   DescIdx = Dev->TxFreeStack[Dev->TxCurPending++];
-  Dev->TxRing.Desc[DescIdx + 1].Addr  = (UINTN) Buffer;
+  Dev->TxRing.Desc[DescIdx + 1].Addr  = (UINTN) DeviceAddress;
   Dev->TxRing.Desc[DescIdx + 1].Len   = (UINT32) BufferSize;
 
   //
-- 
2.7.4

_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel

Reply via email to