public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: Brijesh Singh <brijesh.singh@amd.com>
To: edk2-devel@lists.01.org
Cc: Brijesh Singh <brijesh.singh@amd.com>,
	Ard Biesheuvel <ard.biesheuvel@linaro.org>,
	Jordan Justen <jordan.l.justen@intel.com>,
	Tom Lendacky <thomas.lendacky@amd.com>,
	Laszlo Ersek <lersek@redhat.com>
Subject: [PATCH 4/5] OvmfPkg/VirtioNetDxe: map virtio-net transmit request buffer
Date: Fri,  1 Sep 2017 07:24:04 -0400	[thread overview]
Message-ID: <1504265045-19008-5-git-send-email-brijesh.singh@amd.com> (raw)
In-Reply-To: <1504265045-19008-1-git-send-email-brijesh.singh@amd.com>

When device is behind the IOMMU, driver is require to pass the device
address of transmit buffer for the bus master operations.

The patch uses VirtioMapAllBytesInSharedBuffer() to map transmit buffer
system physical address to the device address.

Since the transmit buffers are returned back to caller in
VirtioNetGetStatus() hence we use OrderCollection library interface to
save the host to device address mapping. After the buffer is succesfully
transmited we do reverse lookup in OrderCollection data structure to get
the host address for the transmitted device address.

Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
---
 OvmfPkg/VirtioNetDxe/VirtioNet.inf      |   1 +
 OvmfPkg/VirtioNetDxe/VirtioNet.h        |  19 +++
 OvmfPkg/VirtioNetDxe/SnpGetStatus.c     |  30 +++-
 OvmfPkg/VirtioNetDxe/SnpSharedHelpers.c | 157 ++++++++++++++++++++
 OvmfPkg/VirtioNetDxe/SnpTransmit.c      |  37 ++++-
 5 files changed, 232 insertions(+), 12 deletions(-)

diff --git a/OvmfPkg/VirtioNetDxe/VirtioNet.inf b/OvmfPkg/VirtioNetDxe/VirtioNet.inf
index a855ad4ac154..9ff6d87e6190 100644
--- a/OvmfPkg/VirtioNetDxe/VirtioNet.inf
+++ b/OvmfPkg/VirtioNetDxe/VirtioNet.inf
@@ -49,6 +49,7 @@ [LibraryClasses]
   DebugLib
   DevicePathLib
   MemoryAllocationLib
+  OrderedCollectionLib
   UefiBootServicesTableLib
   UefiDriverEntryPoint
   UefiLib
diff --git a/OvmfPkg/VirtioNetDxe/VirtioNet.h b/OvmfPkg/VirtioNetDxe/VirtioNet.h
index 3efe95a735d8..d931969af795 100644
--- a/OvmfPkg/VirtioNetDxe/VirtioNet.h
+++ b/OvmfPkg/VirtioNetDxe/VirtioNet.h
@@ -269,6 +269,25 @@ VirtioNetShutdownTx (
   IN OUT VNET_DEV *Dev
   );
 
+EFI_STATUS
+EFIAPI
+VirtioMapTxBuf (
+  IN  VNET_DEV              *Dev,
+  IN  UINT16                Index,
+  IN  EFI_PHYSICAL_ADDRESS  HostAddress,
+  IN  UINTN                 NumberOfBytes,
+  OUT EFI_PHYSICAL_ADDRESS  *DeviceAddress
+  );
+
+EFI_STATUS
+EFIAPI
+VirtioUnmapTxBuf (
+  IN  VNET_DEV              *Dev,
+  IN  UINT16                Index,
+  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..10ca26de6d7a 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
@@ -47,7 +48,8 @@
   @retval EFI_INVALID_PARAMETER One or more of the parameters has an
                                 unsupported value.
   @retval EFI_DEVICE_ERROR      The command could not be sent to the network
-                                interface.
+                                interface or failed to map TxBuf to bus master
+                                address.
   @retval EFI_UNSUPPORTED       This function is not supported by the network
                                 interface.
 
@@ -126,8 +128,10 @@ VirtioNetGetStatus (
       *TxBuf = NULL;
     }
     else {
-      UINT16 UsedElemIdx;
-      UINT32 DescIdx;
+      UINT16                UsedElemIdx;
+      UINT32                DescIdx;
+      EFI_PHYSICAL_ADDRESS  BufferAddress;
+      EFI_PHYSICAL_ADDRESS  DeviceAddress;
 
       //
       // fetch the first descriptor among those that the hypervisor reports
@@ -141,9 +145,27 @@ VirtioNetGetStatus (
       ASSERT (DescIdx < (UINT32) (2 * Dev->TxMaxPending - 1));
 
       //
+      // Ring descriptor contains the device address for the caller buffer.
+      // Lets unmap the device address and find its corresponding system
+      // physical address.
+      //
+      DeviceAddress = Dev->TxRing.Desc[DescIdx + 1].Addr;
+      Status = VirtioUnmapTxBuf (
+                 Dev,
+                 DescIdx + 1,
+                 &BufferAddress,
+                 DeviceAddress
+                 );
+      if (EFI_ERROR (Status)) {
+        Status = EFI_DEVICE_ERROR;
+        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) BufferAddress;
 
       //
       // 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 aeb9e6605f0d..b91ddd3e4ede 100644
--- a/OvmfPkg/VirtioNetDxe/SnpSharedHelpers.c
+++ b/OvmfPkg/VirtioNetDxe/SnpSharedHelpers.c
@@ -14,10 +14,25 @@
 
 **/
 
+#include <Library/BaseLib.h>
 #include <Library/MemoryAllocationLib.h>
+#include <Library/OrderedCollectionLib.h>
 
 #include "VirtioNet.h"
 
+typedef struct {
+  UINT16  Value;
+} USER_KEY;
+
+typedef struct {
+  USER_KEY              Key;
+  EFI_PHYSICAL_ADDRESS  HostAddress;
+  EFI_PHYSICAL_ADDRESS  DeviceAddress;
+  VOID                  *BufMap;
+} USER_STRUCT;
+
+STATIC ORDERED_COLLECTION *Collection;
+
 /**
   Release RX and TX resources on the boundary of the
   EfiSimpleNetworkInitialized state.
@@ -63,3 +78,145 @@ VirtioNetShutdownTx (
 
   FreePool (Dev->TxFreeStack);
 }
+
+STATIC
+INTN
+EFIAPI
+KeyCompare (
+  IN  CONST VOID  *StandaloneKey,
+  IN  CONST VOID  *UserStruct
+  )
+{
+  CONST USER_KEY    *CmpKey;
+  CONST USER_STRUCT *CmpStruct;
+
+  CmpKey = StandaloneKey;
+  CmpStruct = UserStruct;
+
+  return CmpKey->Value < CmpStruct->Key.Value ? -1 :
+         CmpKey->Value > CmpStruct->Key.Value ?  1 :
+         0;
+}
+
+STATIC
+INTN
+EFIAPI
+UserStructCompare (
+  IN CONST VOID *UserStruct1,
+  IN CONST VOID *UserStruct2
+  )
+{
+  CONST USER_STRUCT *CmpStruct1;
+
+  CmpStruct1 = UserStruct1;
+
+  return KeyCompare (&CmpStruct1->Key, UserStruct2);
+}
+
+EFI_STATUS
+EFIAPI
+VirtioMapTxBuf (
+  IN  VNET_DEV               *Dev,
+  IN  UINT16                 Index,
+  IN  EFI_PHYSICAL_ADDRESS   HostAddress,
+  IN  UINTN                  NumberOfBytes,
+  OUT EFI_PHYSICAL_ADDRESS   *DeviceAddress
+  )
+{
+  EFI_STATUS                Status;
+  ORDERED_COLLECTION_ENTRY  *Entry;
+  USER_STRUCT               *UserStruct;
+  EFI_PHYSICAL_ADDRESS      Address;
+  VOID                      *Mapping;
+
+  //
+  // If ordered collection is not initialized then initialize it.
+  //
+  if (Collection == NULL) {
+    Collection = OrderedCollectionInit (UserStructCompare, KeyCompare);
+    if (Collection == NULL) {
+      return EFI_OUT_OF_RESOURCES;
+    }
+  }
+
+  UserStruct = AllocatePool (sizeof (*UserStruct));
+  if (UserStruct == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  Status = VirtioMapAllBytesInSharedBuffer (
+             Dev->VirtIo,
+             VirtioOperationBusMasterRead,
+             (VOID *) (UINTN) HostAddress,
+             NumberOfBytes,
+             &Address,
+             &Mapping
+             );
+  if (EFI_ERROR (Status)) {
+    goto ReleaseUserStruct;
+  }
+
+  UserStruct->Key.Value = Index;
+  UserStruct->HostAddress = HostAddress;
+  UserStruct->DeviceAddress = Address;
+  UserStruct->BufMap = Mapping;
+
+  Status = OrderedCollectionInsert (Collection, &Entry, UserStruct);
+  switch (Status) {
+  case RETURN_OUT_OF_RESOURCES:
+    Status = EFI_OUT_OF_RESOURCES;
+    goto UnmapBuffer;
+  case RETURN_ALREADY_STARTED:
+    Status = EFI_INVALID_PARAMETER;
+    goto UnmapBuffer;
+  default:
+    ASSERT (Status == RETURN_SUCCESS);
+    break;
+  }
+
+  ASSERT (OrderedCollectionUserStruct (Entry) == UserStruct);
+
+  *DeviceAddress = Address;
+  return EFI_SUCCESS;
+
+UnmapBuffer:
+  Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, Mapping);
+
+ReleaseUserStruct:
+  FreePool (UserStruct);
+  return Status;
+}
+
+EFI_STATUS
+EFIAPI
+VirtioUnmapTxBuf (
+  IN  VNET_DEV               *Dev,
+  IN  UINT16                 Index,
+  OUT EFI_PHYSICAL_ADDRESS   *HostAddress,
+  IN  EFI_PHYSICAL_ADDRESS   DeviceAddress
+  )
+{
+  USER_KEY                  StandaloneKey;
+  ORDERED_COLLECTION_ENTRY  *Entry;
+  USER_STRUCT               *UserStruct;
+  VOID                      *Ptr;
+  EFI_STATUS                Status;
+
+  StandaloneKey.Value = Index;
+  Entry = OrderedCollectionFind (Collection, &StandaloneKey);
+  if (Entry == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  OrderedCollectionDelete (Collection, Entry, &Ptr);
+
+  UserStruct = Ptr;
+  ASSERT (UserStruct->DeviceAddress == DeviceAddress);
+  ASSERT (UserStruct->Key.Value == Index);
+
+  *HostAddress =  UserStruct->HostAddress;
+  Status = Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, UserStruct->BufMap);
+  FreePool (UserStruct);
+
+  return Status;
+}
diff --git a/OvmfPkg/VirtioNetDxe/SnpTransmit.c b/OvmfPkg/VirtioNetDxe/SnpTransmit.c
index 7ca40d5d0650..1bd6e0d70d7c 100644
--- a/OvmfPkg/VirtioNetDxe/SnpTransmit.c
+++ b/OvmfPkg/VirtioNetDxe/SnpTransmit.c
@@ -55,7 +55,8 @@
   @retval EFI_INVALID_PARAMETER One or more of the parameters has an
                                 unsupported value.
   @retval EFI_DEVICE_ERROR      The command could not be sent to the network
-                                interface.
+                                interface or failed to map the Buffer to
+                                bus master address.
   @retval EFI_UNSUPPORTED       This function is not supported by the network
                                 interface.
 
@@ -73,11 +74,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 +146,29 @@ VirtioNetTransmit (
   }
 
   //
-  // virtio-0.9.5, 2.4.1 Supplying Buffers to The Device
+  // Get the available descriptor
   //
   DescIdx = Dev->TxFreeStack[Dev->TxCurPending++];
-  Dev->TxRing.Desc[DescIdx + 1].Addr  = (UINTN) Buffer;
+
+  //
+  // Map the transmit buffer system physical address to device address.
+  //
+  Status = VirtioMapTxBuf (
+             Dev,
+             DescIdx + 1,
+             (EFI_PHYSICAL_ADDRESS) (UINTN) Buffer,
+             BufferSize,
+             &DeviceAddress
+             );
+  if (EFI_ERROR (Status)) {
+    Status = EFI_DEVICE_ERROR;
+    goto Exit;
+  }
+
+  //
+  // virtio-0.9.5, 2.4.1 Supplying Buffers to The Device
+  //
+  Dev->TxRing.Desc[DescIdx + 1].Addr  = DeviceAddress;
   Dev->TxRing.Desc[DescIdx + 1].Len   = (UINT32) BufferSize;
 
   //
-- 
2.7.4



  parent reply	other threads:[~2017-09-01 11:21 UTC|newest]

Thread overview: 21+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-09-01 11:24 [PATCH 0/5] OvmfPkg/VirtioNetDxe: map host address to device address Brijesh Singh
2017-09-01 11:24 ` [PATCH 1/5] OvmfPkg/VirtioNetDxe: map VRING using VirtioRingMap() Brijesh Singh
2017-09-05 11:47   ` Laszlo Ersek
2017-09-05 18:57     ` Brijesh Singh
2017-09-05 20:17       ` Laszlo Ersek
2017-09-05 21:11         ` Ard Biesheuvel
2017-09-05 21:59           ` Laszlo Ersek
2017-09-05 22:18             ` Ard Biesheuvel
2017-09-05 22:37               ` Laszlo Ersek
2017-09-05 23:03                 ` Ard Biesheuvel
2017-09-01 11:24 ` [PATCH 2/5] OvmfPkg/VirtioNetDxe: alloc RxBuf using AllocateSharedPages() Brijesh Singh
2017-09-05 15:06   ` Laszlo Ersek
2017-09-01 11:24 ` [PATCH 3/5] OvmfPkg/VirtioNetDxe: dynamically alloc transmit header Brijesh Singh
2017-09-06  9:11   ` Laszlo Ersek
2017-09-01 11:24 ` Brijesh Singh [this message]
2017-09-05 12:41   ` [PATCH 4/5] OvmfPkg/VirtioNetDxe: map virtio-net transmit request buffer Laszlo Ersek
2017-09-05 12:44     ` Laszlo Ersek
2017-09-06  8:11     ` Laszlo Ersek
2017-09-01 11:24 ` [PATCH 5/5] OvmfPkg/VirtioNetDxe: negotiate VIRTIO_F_IOMMU_PLATFORM Brijesh Singh
2017-09-06  7:33   ` Laszlo Ersek
2017-09-07 22:55 ` [PATCH 0/5] OvmfPkg/VirtioNetDxe: map host address to device address Laszlo Ersek

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=1504265045-19008-5-git-send-email-brijesh.singh@amd.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