Contributed-under: TianoCore Contribution Agreement 1.0

Signed-off-by: Laszlo Ersek <ler...@redhat.com>
---
 OvmfPkg/VirtioNetDxe/SnpGetStatus.c |  160 ++++++++++++++++++++++++++++++++
 OvmfPkg/VirtioNetDxe/SnpTransmit.c  |  171 +++++++++++++++++++++++++++++++++++
 2 files changed, 331 insertions(+), 0 deletions(-)
 create mode 100644 OvmfPkg/VirtioNetDxe/SnpGetStatus.c
 create mode 100644 OvmfPkg/VirtioNetDxe/SnpTransmit.c

diff --git a/OvmfPkg/VirtioNetDxe/SnpGetStatus.c 
b/OvmfPkg/VirtioNetDxe/SnpGetStatus.c
new file mode 100644
index 0000000..6acd17f
--- /dev/null
+++ b/OvmfPkg/VirtioNetDxe/SnpGetStatus.c
@@ -0,0 +1,160 @@
+/** @file
+
+  Implementation of the SNP.GetStatus() function and its private helpers if
+  any.
+
+  Copyright (C) 2013, Red Hat, Inc.
+
+  UEFI API documentation:
+  Copyright (c) 2006 - 2010, Intel Corporation. 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
+  distribution. The full text of the license may be found at
+  http://opensource.org/licenses/bsd-license.php
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT
+  WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <Library/BaseLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+
+#include "VirtioNet.h"
+
+/**
+  Reads the current interrupt status and recycled transmit buffer status from
+  a network interface.
+
+  @param  This            The protocol instance pointer.
+  @param  InterruptStatus A pointer to the bit mask of the currently active
+                          interrupts If this is NULL, the interrupt status will
+                          not be read from the device. If this is not NULL, the
+                          interrupt status will be read from the device. When
+                          the  interrupt status is read, it will also be
+                          cleared. Clearing the transmit  interrupt does not
+                          empty the recycled transmit buffer array.
+  @param  TxBuf           Recycled transmit buffer address. The network
+                          interface will not transmit if its internal recycled
+                          transmit buffer array is full. Reading the transmit
+                          buffer does not clear the transmit interrupt. If this
+                          is NULL, then the transmit buffer status will not be
+                          read. If there are no transmit buffers to recycle and
+                          TxBuf is not NULL, * TxBuf will be set to NULL.
+
+  @retval EFI_SUCCESS           The status of the network interface was
+                                retrieved.
+  @retval EFI_NOT_STARTED       The network interface has not been started.
+  @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.
+  @retval EFI_UNSUPPORTED       This function is not supported by the network
+                                interface.
+
+**/
+
+EFI_STATUS
+EFIAPI
+VirtioNetGetStatus (
+  IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+  OUT UINT32                     *InterruptStatus OPTIONAL,
+  OUT VOID                       **TxBuf OPTIONAL
+  )
+{
+  VNET_DEV   *Dev;
+  EFI_TPL    OldTpl;
+  EFI_STATUS Status;
+  UINT16     RxCurUsed;
+  UINT16     TxCurUsed;
+
+  if (This == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Dev = VIRTIO_NET_FROM_SNP (This);
+  OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+  switch (Dev->Snm.State) {
+  case EfiSimpleNetworkStopped:
+    Status = EFI_NOT_STARTED;
+    goto Exit;
+  case EfiSimpleNetworkStarted:
+    Status = EFI_DEVICE_ERROR;
+    goto Exit;
+  default:
+    break;
+  }
+
+  //
+  // update link status
+  //
+  if (Dev->Snm.MediaPresentSupported) {
+    UINT16 LinkStatus;
+
+    Status = VIRTIO_CFG_READ (Dev, VhdrLinkStatus, &LinkStatus);
+    if (EFI_ERROR (Status)) {
+      goto Exit;
+    }
+    Dev->Snm.MediaPresent = !!(LinkStatus & VIRTIO_NET_S_LINK_UP);
+  }
+
+  //
+  // virtio-0.9.5, 2.4.2 Receiving Used Buffers From the Device
+  //
+  MemoryFence ();
+  RxCurUsed = *Dev->RxRing.Used.Idx;
+  TxCurUsed = *Dev->TxRing.Used.Idx;
+
+  if (InterruptStatus != NULL) {
+    //
+    // report the receive interrupt if there is data available for reception,
+    // report the transmit interrupt if we have transmitted at least one buffer
+    //
+    *InterruptStatus = 0;
+    if (Dev->RxLastUsed != RxCurUsed) {
+      *InterruptStatus |= EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT;
+    }
+    if (Dev->TxLastUsed != TxCurUsed) {
+      ASSERT (Dev->TxCurPending > 0);
+      *InterruptStatus |= EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT;
+    }
+  }
+
+  if (TxBuf != NULL) {
+    if (Dev->TxLastUsed == TxCurUsed) {
+      *TxBuf = NULL;
+    }
+    else {
+      UINT16 UsedElemIdx;
+      UINT32 DescIdx;
+
+      //
+      // fetch the first descriptor among those that the hypervisor reports
+      // completed
+      //
+      ASSERT (Dev->TxCurPending > 0);
+      ASSERT (Dev->TxCurPending <= Dev->TxMaxPending);
+
+      UsedElemIdx = Dev->TxLastUsed++ % Dev->TxRing.QueueSize;
+      DescIdx = Dev->TxRing.Used.UsedElem[UsedElemIdx].Id;
+      ASSERT (DescIdx < 2 * Dev->TxMaxPending - 1);
+
+      //
+      // report buffer address to caller that has been enqueued by caller
+      //
+      *TxBuf = (VOID *) Dev->TxRing.Desc[DescIdx + 1].Addr;
+
+      //
+      // now this descriptor can be used again to enqueue a transmit buffer
+      //
+      Dev->TxFreeStack[--Dev->TxCurPending] = (UINT16) DescIdx;
+    }
+  }
+
+  Status = EFI_SUCCESS;
+
+Exit:
+  gBS->RestoreTPL (OldTpl);
+  return Status;
+}
diff --git a/OvmfPkg/VirtioNetDxe/SnpTransmit.c 
b/OvmfPkg/VirtioNetDxe/SnpTransmit.c
new file mode 100644
index 0000000..c0793a6
--- /dev/null
+++ b/OvmfPkg/VirtioNetDxe/SnpTransmit.c
@@ -0,0 +1,171 @@
+/** @file
+
+  Implementation of the SNP.Transmit() function and its private helpers if any.
+
+  Copyright (C) 2013, Red Hat, Inc.
+
+  UEFI API documentation:
+  Copyright (c) 2006 - 2010, Intel Corporation. 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
+  distribution. The full text of the license may be found at
+  http://opensource.org/licenses/bsd-license.php
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT
+  WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+
+#include "VirtioNet.h"
+
+/**
+  Places a packet in the transmit queue of a network interface.
+
+  @param  This       The protocol instance pointer.
+  @param  HeaderSize The size, in bytes, of the media header to be filled in by
+                     the Transmit() function. If HeaderSize is non-zero, then
+                     it must be equal to This->Mode->MediaHeaderSize and the
+                     DestAddr and Protocol parameters must not be NULL.
+  @param  BufferSize The size, in bytes, of the entire packet (media header and
+                     data) to be transmitted through the network interface.
+  @param  Buffer     A pointer to the packet (media header followed by data) to
+                     be transmitted. This parameter cannot be NULL. If
+                     HeaderSize is zero, then the media header in Buffer must
+                     already be filled in by the caller. If HeaderSize is
+                     non-zero, then the media header will be filled in by the
+                     Transmit() function.
+  @param  SrcAddr    The source HW MAC address. If HeaderSize is zero, then
+                     this parameter is ignored. If HeaderSize is non-zero and
+                     SrcAddr is NULL, then This->Mode->CurrentAddress is used
+                     for the source HW MAC address.
+  @param  DestAddr   The destination HW MAC address. If HeaderSize is zero,
+                     then this parameter is ignored.
+  @param  Protocol   The type of header to build. If HeaderSize is zero, then
+                     this parameter is ignored. See RFC 1700, section "Ether
+                     Types", for examples.
+
+  @retval EFI_SUCCESS           The packet was placed on the transmit queue.
+  @retval EFI_NOT_STARTED       The network interface has not been started.
+  @retval EFI_NOT_READY         The network interface is too busy to accept
+                                this transmit request.
+  @retval EFI_BUFFER_TOO_SMALL  The BufferSize parameter is too small.
+  @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.
+  @retval EFI_UNSUPPORTED       This function is not supported by the network
+                                interface.
+
+**/
+
+EFI_STATUS
+EFIAPI
+VirtioNetTransmit (
+  IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+  IN UINTN                       HeaderSize,
+  IN UINTN                       BufferSize,
+  IN /* +OUT! */ VOID            *Buffer,
+  IN EFI_MAC_ADDRESS             *SrcAddr  OPTIONAL,
+  IN EFI_MAC_ADDRESS             *DestAddr OPTIONAL,
+  IN UINT16                      *Protocol OPTIONAL
+  )
+{
+  VNET_DEV   *Dev;
+  EFI_TPL    OldTpl;
+  EFI_STATUS Status;
+  UINT16     DescIdx;
+  UINT16     AvailIdx;
+
+  if (This == NULL || BufferSize == 0 || Buffer == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Dev = VIRTIO_NET_FROM_SNP (This);
+  OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+  switch (Dev->Snm.State) {
+  case EfiSimpleNetworkStopped:
+    Status = EFI_NOT_STARTED;
+    goto Exit;
+  case EfiSimpleNetworkStarted:
+    Status = EFI_DEVICE_ERROR;
+    goto Exit;
+  default:
+    break;
+  }
+
+  if (BufferSize < Dev->Snm.MediaHeaderSize) {
+    Status = EFI_BUFFER_TOO_SMALL;
+    goto Exit;
+  }
+  if (BufferSize > Dev->Snm.MediaHeaderSize + Dev->Snm.MaxPacketSize) {
+    Status = EFI_INVALID_PARAMETER;
+    goto Exit;
+  }
+
+  //
+  // check if we have room for transmission
+  //
+  ASSERT (Dev->TxCurPending <= Dev->TxMaxPending);
+  if (Dev->TxCurPending == Dev->TxMaxPending) {
+    Status = EFI_NOT_READY;
+    goto Exit;
+  }
+
+  //
+  // the caller may want us to fill in the media header:
+  // dst MAC, src MAC, Ethertype
+  //
+  if (HeaderSize != 0) {
+    UINT8 *Ptr;
+
+    if (HeaderSize != Dev->Snm.MediaHeaderSize ||
+        DestAddr == NULL || Protocol == NULL) {
+      Status = EFI_INVALID_PARAMETER;
+      goto Exit;
+    }
+    Ptr = Buffer;
+    ASSERT (SIZE_OF_VNET (VhdrMac) <= sizeof (EFI_MAC_ADDRESS));
+
+    CopyMem (Ptr, DestAddr, SIZE_OF_VNET (VhdrMac));
+    Ptr += SIZE_OF_VNET (VhdrMac);
+
+    CopyMem (Ptr,
+      (SrcAddr == NULL) ? &Dev->Snm.CurrentAddress : SrcAddr,
+      SIZE_OF_VNET (VhdrMac));
+    Ptr += SIZE_OF_VNET (VhdrMac);
+
+    *Ptr++ = (UINT8) (*Protocol >> 8);
+    *Ptr++ = (UINT8) *Protocol;
+
+    ASSERT (Ptr - (UINT8 *) Buffer == Dev->Snm.MediaHeaderSize);
+  }
+
+  //
+  // 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].Len   = (UINT32) BufferSize;
+
+  //
+  // the available index is never written by the host, we can read it back
+  // without a barrier
+  //
+  AvailIdx = *Dev->TxRing.Avail.Idx;
+  Dev->TxRing.Avail.Ring[AvailIdx++ % Dev->TxRing.QueueSize] = DescIdx;
+
+  MemoryFence ();
+  *Dev->TxRing.Avail.Idx = AvailIdx;
+
+  MemoryFence ();
+  Status = VIRTIO_CFG_WRITE (Dev, Generic.VhdrQueueNotify, VIRTIO_NET_Q_TX);
+
+Exit:
+  gBS->RestoreTPL (OldTpl);
+  return Status;
+}
-- 
1.7.1



------------------------------------------------------------------------------
AlienVault Unified Security Management (USM) platform delivers complete
security visibility with the essential security capabilities. Easily and
efficiently configure, manage, and operate all of your security controls
from a single console and one unified framework. Download a free trial.
http://p.sf.net/sfu/alienvault_d2d
_______________________________________________
edk2-devel mailing list
edk2-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/edk2-devel

Reply via email to