Update VirtioNetTransmit() to map the callers transmit buffer to a device address and use the DeviceAddress in vring descriptors.
Since the transmit buffers are returned back to caller in VirtioNetGetStatus() hence we maintain a simple list to map DeviceAddress to HostAddress. The list is used for mapping to HostAddress after the data is succesfully transmitted. 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 | 115 ++++++++++++++++++++ OvmfPkg/VirtioNetDxe/SnpTransmit.c | 26 ++++- OvmfPkg/VirtioRngDxe/VirtioRng.c | 2 +- 5 files changed, 169 insertions(+), 10 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 6e7166144f2d..3dbfc272980a 100644 --- a/OvmfPkg/VirtioNetDxe/SnpSharedHelpers.c +++ b/OvmfPkg/VirtioNetDxe/SnpSharedHelpers.c @@ -14,10 +14,29 @@ **/ +#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) + +// +// List of Txbuf queued +// +STATIC LIST_ENTRY mTxBufMapList = INITIALIZE_LIST_HEAD_VARIABLE ( + mTxBufMapList + ); + /** Release RX and TX resources on the boundary of the EfiSimpleNetworkInitialized state. @@ -61,3 +80,99 @@ 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 = VirtioMapAllBytesInSharedBuffer ( + Dev->VirtIo, + VirtioOperationBusMasterRead, + (VOID *) (UINTN) Private->HostAddress, + NumberOfBytes, + &Private->DeviceAddress, + &Private->Mapping + ); + if (EFI_ERROR (Status)) { + goto FreePool; + } + + *DeviceAddress = Private->DeviceAddress; + + // + // Add the mapping information into internal list so that we can retrieve + // the HostAddress from Unmap(). + // + InsertTailList (&mTxBufMapList, &Private->Link); + + return EFI_SUCCESS; + +FreePool: + FreePool (Private); + return Status; +} + +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 = Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, Private->Mapping); + if (EFI_ERROR (Status)) { + return Status; + } + + *HostAddress = Private->HostAddress; + + RemoveEntryList (&Private->Link); + FreePool (Private); + + return EFI_SUCCESS; +} diff --git a/OvmfPkg/VirtioNetDxe/SnpTransmit.c b/OvmfPkg/VirtioNetDxe/SnpTransmit.c index 7ca40d5d0650..9d7d017d5a6f 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,23 @@ 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; // diff --git a/OvmfPkg/VirtioRngDxe/VirtioRng.c b/OvmfPkg/VirtioRngDxe/VirtioRng.c index fc01f1996654..b19d90901430 100644 --- a/OvmfPkg/VirtioRngDxe/VirtioRng.c +++ b/OvmfPkg/VirtioRngDxe/VirtioRng.c @@ -162,7 +162,7 @@ VirtioRngGetRNG ( Dev = VIRTIO_ENTROPY_SOURCE_FROM_RNG (This); // - // Map the Buffers system phyiscal address to device address + // Map the Buffer host address to device address // Status = VirtioMapAllBytesInSharedBuffer ( Dev->VirtIo, -- 2.7.4 _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel