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 <[email protected]> Cc: Jordan Justen <[email protected]> Cc: Tom Lendacky <[email protected]> Cc: Laszlo Ersek <[email protected]> Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Brijesh Singh <[email protected]> --- 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 [email protected] https://lists.01.org/mailman/listinfo/edk2-devel

