summaryrefslogtreecommitdiff
path: root/OvmfPkg/VirtioNetDxe/SnpInitialize.c
diff options
context:
space:
mode:
Diffstat (limited to 'OvmfPkg/VirtioNetDxe/SnpInitialize.c')
-rw-r--r--OvmfPkg/VirtioNetDxe/SnpInitialize.c490
1 files changed, 0 insertions, 490 deletions
diff --git a/OvmfPkg/VirtioNetDxe/SnpInitialize.c b/OvmfPkg/VirtioNetDxe/SnpInitialize.c
deleted file mode 100644
index 223030af9e..0000000000
--- a/OvmfPkg/VirtioNetDxe/SnpInitialize.c
+++ /dev/null
@@ -1,490 +0,0 @@
-/** @file
-
- Implementation of the SNP.Initialize() function and its private helpers if
- any.
-
- Copyright (C) 2013, Red Hat, Inc.
- 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/MemoryAllocationLib.h>
-#include <Library/UefiBootServicesTableLib.h>
-
-#include "VirtioNet.h"
-
-/**
- Initialize a virtio ring for a specific transfer direction of the virtio-net
- device.
-
- This function may only be called by VirtioNetInitialize().
-
- @param[in,out] Dev The VNET_DEV driver instance about to enter the
- EfiSimpleNetworkInitialized state.
- @param[in] Selector Identifies the transfer direction (virtio queue) of
- the network device.
- @param[out] Ring The virtio-ring inside the VNET_DEV structure,
- corresponding to Selector.
-
- @retval EFI_UNSUPPORTED The queue size reported by the virtio-net device is
- too small.
- @return Status codes from VIRTIO_CFG_WRITE(),
- VIRTIO_CFG_READ() and VirtioRingInit().
- @retval EFI_SUCCESS Ring initialized.
-*/
-
-STATIC
-EFI_STATUS
-EFIAPI
-VirtioNetInitRing (
- IN OUT VNET_DEV *Dev,
- IN UINT16 Selector,
- OUT VRING *Ring
- )
-{
- EFI_STATUS Status;
- UINT16 QueueSize;
-
- //
- // step 4b -- allocate selected queue
- //
- Status = Dev->VirtIo->SetQueueSel (Dev->VirtIo, Selector);
- if (EFI_ERROR (Status)) {
- return Status;
- }
- Status = Dev->VirtIo->GetQueueNumMax (Dev->VirtIo, &QueueSize);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- //
- // For each packet (RX and TX alike), we need two descriptors:
- // one for the virtio-net request header, and another one for the data
- //
- if (QueueSize < 2) {
- return EFI_UNSUPPORTED;
- }
- Status = VirtioRingInit (QueueSize, Ring);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- //
- // Additional steps for MMIO: align the queue appropriately, and set the
- // size. If anything fails from here on, we must release the ring resources.
- //
- Status = Dev->VirtIo->SetQueueNum (Dev->VirtIo, QueueSize);
- if (EFI_ERROR (Status)) {
- goto ReleaseQueue;
- }
-
- Status = Dev->VirtIo->SetQueueAlign (Dev->VirtIo, EFI_PAGE_SIZE);
- if (EFI_ERROR (Status)) {
- goto ReleaseQueue;
- }
-
- //
- // step 4c -- report GPFN (guest-physical frame number) of queue
- //
- Status = Dev->VirtIo->SetQueueAddress (Dev->VirtIo,
- (UINT32) ((UINTN) Ring->Base >> EFI_PAGE_SHIFT));
- if (EFI_ERROR (Status)) {
- goto ReleaseQueue;
- }
-
- return EFI_SUCCESS;
-
-ReleaseQueue:
- VirtioRingUninit (Ring);
-
- return Status;
-}
-
-
-/**
- Set up static scaffolding for the VirtioNetTransmit() and
- VirtioNetGetStatus() SNP methods.
-
- This function may only be called by VirtioNetInitialize().
-
- The structures laid out and resources configured include:
- - fully populate the TX queue with a static pattern of virtio descriptor
- chains,
- - tracking of heads of free descriptor chains from the above,
- - one common virtio-net request header (never modified by the host) for all
- pending TX packets,
- - select polling over TX interrupt.
-
- @param[in,out] Dev The VNET_DEV driver instance about to enter the
- EfiSimpleNetworkInitialized state.
-
- @retval EFI_OUT_OF_RESOURCES Failed to allocate the stack to track the heads
- of free descriptor chains.
- @retval EFI_SUCCESS TX setup successful.
-*/
-
-STATIC
-EFI_STATUS
-EFIAPI
-VirtioNetInitTx (
- IN OUT VNET_DEV *Dev
- )
-{
- UINTN PktIdx;
-
- Dev->TxMaxPending = (UINT16) MIN (Dev->TxRing.QueueSize / 2,
- VNET_MAX_PENDING);
- Dev->TxCurPending = 0;
- Dev->TxFreeStack = AllocatePool (Dev->TxMaxPending *
- sizeof *Dev->TxFreeStack);
- if (Dev->TxFreeStack == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- for (PktIdx = 0; PktIdx < Dev->TxMaxPending; ++PktIdx) {
- UINT16 DescIdx;
-
- DescIdx = (UINT16) (2 * PktIdx);
- Dev->TxFreeStack[PktIdx] = DescIdx;
-
- //
- // For each possibly pending packet, lay out the descriptor for the common
- // (unmodified by the host) virtio-net request header.
- //
- Dev->TxRing.Desc[DescIdx].Addr = (UINTN) &Dev->TxSharedReq;
- Dev->TxRing.Desc[DescIdx].Len = sizeof Dev->TxSharedReq;
- Dev->TxRing.Desc[DescIdx].Flags = VRING_DESC_F_NEXT;
- Dev->TxRing.Desc[DescIdx].Next = (UINT16) (DescIdx + 1);
-
- //
- // The second descriptor of each pending TX packet is updated on the fly,
- // but it always terminates the descriptor chain of the packet.
- //
- Dev->TxRing.Desc[DescIdx + 1].Flags = 0;
- }
-
- //
- // virtio-0.9.5, Appendix C, Packet Transmission
- //
- Dev->TxSharedReq.Flags = 0;
- Dev->TxSharedReq.GsoType = VIRTIO_NET_HDR_GSO_NONE;
-
- //
- // virtio-0.9.5, 2.4.2 Receiving Used Buffers From the Device
- //
- MemoryFence ();
- Dev->TxLastUsed = *Dev->TxRing.Used.Idx;
- ASSERT (Dev->TxLastUsed == 0);
-
- //
- // want no interrupt when a transmit completes
- //
- *Dev->TxRing.Avail.Flags = (UINT16) VRING_AVAIL_F_NO_INTERRUPT;
-
- return EFI_SUCCESS;
-}
-
-
-/**
- Set up static scaffolding for the VirtioNetReceive() SNP method and enable
- live device operation.
-
- This function may only be called as VirtioNetInitialize()'s final step.
-
- The structures laid out and resources configured include:
- - destination area for the host to write virtio-net request headers and
- packet data into,
- - select polling over RX interrupt,
- - fully populate the RX queue with a static pattern of virtio descriptor
- chains.
-
- @param[in,out] Dev The VNET_DEV driver instance about to enter the
- EfiSimpleNetworkInitialized state.
-
- @retval EFI_OUT_OF_RESOURCES Failed to allocate RX destination area.
- @return Status codes from VIRTIO_CFG_WRITE().
- @retval EFI_SUCCESS RX setup successful. The device is live and may
- already be writing to the receive area.
-*/
-
-STATIC
-EFI_STATUS
-EFIAPI
-VirtioNetInitRx (
- IN OUT VNET_DEV *Dev
- )
-{
- EFI_STATUS Status;
- UINTN RxBufSize;
- UINT16 RxAlwaysPending;
- UINTN PktIdx;
- UINT16 DescIdx;
- UINT8 *RxPtr;
-
- //
- // For each incoming packet we must supply two descriptors:
- // - the recipient for the virtio-net request header, plus
- // - the recipient for the network data (which consists of Ethernet header
- // and Ethernet payload).
- //
- RxBufSize = sizeof (VIRTIO_NET_REQ) +
- (Dev->Snm.MediaHeaderSize + Dev->Snm.MaxPacketSize);
-
- //
- // Limit the number of pending RX packets if the queue is big. The division
- // by two is due to the above "two descriptors per packet" trait.
- //
- RxAlwaysPending = (UINT16) MIN (Dev->RxRing.QueueSize / 2, VNET_MAX_PENDING);
-
- Dev->RxBuf = AllocatePool (RxAlwaysPending * RxBufSize);
- if (Dev->RxBuf == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- //
- // virtio-0.9.5, 2.4.2 Receiving Used Buffers From the Device
- //
- MemoryFence ();
- Dev->RxLastUsed = *Dev->RxRing.Used.Idx;
- ASSERT (Dev->RxLastUsed == 0);
-
- //
- // virtio-0.9.5, 2.4.2 Receiving Used Buffers From the Device:
- // the host should not send interrupts, we'll poll in VirtioNetReceive()
- // and VirtioNetIsPacketAvailable().
- //
- *Dev->RxRing.Avail.Flags = (UINT16) VRING_AVAIL_F_NO_INTERRUPT;
-
- //
- // now set up a separate, two-part descriptor chain for each RX packet, and
- // link each chain into (from) the available ring as well
- //
- DescIdx = 0;
- RxPtr = Dev->RxBuf;
- for (PktIdx = 0; PktIdx < RxAlwaysPending; ++PktIdx) {
- //
- // virtio-0.9.5, 2.4.1.2 Updating the Available Ring
- // invisible to the host until we update the Index Field
- //
- Dev->RxRing.Avail.Ring[PktIdx] = DescIdx;
-
- //
- // virtio-0.9.5, 2.4.1.1 Placing Buffers into the Descriptor Table
- //
- Dev->RxRing.Desc[DescIdx].Addr = (UINTN) RxPtr;
- Dev->RxRing.Desc[DescIdx].Len = sizeof (VIRTIO_NET_REQ);
- Dev->RxRing.Desc[DescIdx].Flags = VRING_DESC_F_WRITE | VRING_DESC_F_NEXT;
- Dev->RxRing.Desc[DescIdx].Next = (UINT16) (DescIdx + 1);
- RxPtr += Dev->RxRing.Desc[DescIdx++].Len;
-
- Dev->RxRing.Desc[DescIdx].Addr = (UINTN) RxPtr;
- Dev->RxRing.Desc[DescIdx].Len = (UINT32) (RxBufSize -
- sizeof (VIRTIO_NET_REQ));
- Dev->RxRing.Desc[DescIdx].Flags = VRING_DESC_F_WRITE;
- RxPtr += Dev->RxRing.Desc[DescIdx++].Len;
- }
-
- //
- // virtio-0.9.5, 2.4.1.3 Updating the Index Field
- //
- MemoryFence ();
- *Dev->RxRing.Avail.Idx = RxAlwaysPending;
-
- //
- // At this point reception may already be running. In order to make it sure,
- // kick the hypervisor. If we fail to kick it, we must first abort reception
- // before tearing down anything, because reception may have been already
- // running even without the kick.
- //
- // virtio-0.9.5, 2.4.1.4 Notifying the Device
- //
- MemoryFence ();
- Status = Dev->VirtIo->SetQueueNotify (Dev->VirtIo, VIRTIO_NET_Q_RX);
- if (EFI_ERROR (Status)) {
- Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, 0);
- FreePool (Dev->RxBuf);
- }
-
- return Status;
-}
-
-
-/**
- Resets a network adapter and allocates the transmit and receive buffers
- required by the network interface; optionally, also requests allocation of
- additional transmit and receive buffers.
-
- @param This The protocol instance pointer.
- @param ExtraRxBufferSize The size, in bytes, of the extra receive buffer
- space that the driver should allocate for the
- network interface. Some network interfaces will not
- be able to use the extra buffer, and the caller
- will not know if it is actually being used.
- @param ExtraTxBufferSize The size, in bytes, of the extra transmit buffer
- space that the driver should allocate for the
- network interface. Some network interfaces will not
- be able to use the extra buffer, and the caller
- will not know if it is actually being used.
-
- @retval EFI_SUCCESS The network interface was initialized.
- @retval EFI_NOT_STARTED The network interface has not been started.
- @retval EFI_OUT_OF_RESOURCES There was not enough memory for the transmit
- and receive buffers.
- @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
-VirtioNetInitialize (
- IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
- IN UINTN ExtraRxBufferSize OPTIONAL,
- IN UINTN ExtraTxBufferSize OPTIONAL
- )
-{
- VNET_DEV *Dev;
- EFI_TPL OldTpl;
- EFI_STATUS Status;
- UINT8 NextDevStat;
- UINT32 Features;
-
- if (This == NULL) {
- return EFI_INVALID_PARAMETER;
- }
- if (ExtraRxBufferSize > 0 || ExtraTxBufferSize > 0) {
- return EFI_UNSUPPORTED;
- }
-
- Dev = VIRTIO_NET_FROM_SNP (This);
- OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
- if (Dev->Snm.State != EfiSimpleNetworkStarted) {
- Status = EFI_NOT_STARTED;
- goto InitFailed;
- }
-
- //
- // In the EfiSimpleNetworkStarted state the virtio-net device has status
- // value 0 (= reset) -- see the state diagram, the full call chain to
- // the end of VirtioNetGetFeatures() (considering we're here now),
- // the DeviceFailed label below, and VirtioNetShutdown().
- //
- // Accordingly, the below is a subsequence of the steps found in the
- // virtio-0.9.5 spec, 2.2.1 Device Initialization Sequence.
- //
- NextDevStat = VSTAT_ACK; // step 2 -- acknowledge device presence
- Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);
- if (EFI_ERROR (Status)) {
- goto InitFailed;
- }
-
- NextDevStat |= VSTAT_DRIVER; // step 3 -- we know how to drive it
- Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);
- if (EFI_ERROR (Status)) {
- goto DeviceFailed;
- }
-
- //
- // Set Page Size - MMIO VirtIo Specific
- //
- Status = Dev->VirtIo->SetPageSize (Dev->VirtIo, EFI_PAGE_SIZE);
- if (EFI_ERROR (Status)) {
- goto DeviceFailed;
- }
-
- //
- // step 4a -- retrieve features. Note that we're past validating required
- // features in VirtioNetGetFeatures().
- //
- Status = Dev->VirtIo->GetDeviceFeatures (Dev->VirtIo, &Features);
- if (EFI_ERROR (Status)) {
- goto DeviceFailed;
- }
-
- ASSERT (Features & VIRTIO_NET_F_MAC);
- ASSERT (Dev->Snm.MediaPresentSupported ==
- !!(Features & VIRTIO_NET_F_STATUS));
-
- //
- // step 4b, 4c -- allocate and report virtqueues
- //
- Status = VirtioNetInitRing (Dev, VIRTIO_NET_Q_RX, &Dev->RxRing);
- if (EFI_ERROR (Status)) {
- goto DeviceFailed;
- }
-
- Status = VirtioNetInitRing (Dev, VIRTIO_NET_Q_TX, &Dev->TxRing);
- if (EFI_ERROR (Status)) {
- goto ReleaseRxRing;
- }
-
- //
- // step 5 -- keep only the features we want
- //
- Features &= VIRTIO_NET_F_MAC | VIRTIO_NET_F_STATUS;
- Status = Dev->VirtIo->SetGuestFeatures (Dev->VirtIo, Features);
- if (EFI_ERROR (Status)) {
- goto ReleaseTxRing;
- }
-
- //
- // step 6 -- virtio-net initialization complete
- //
- NextDevStat |= VSTAT_DRIVER_OK;
- Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);
- if (EFI_ERROR (Status)) {
- goto ReleaseTxRing;
- }
-
- Status = VirtioNetInitTx (Dev);
- if (EFI_ERROR (Status)) {
- goto AbortDevice;
- }
-
- //
- // start receiving
- //
- Status = VirtioNetInitRx (Dev);
- if (EFI_ERROR (Status)) {
- goto ReleaseTxAux;
- }
-
- Dev->Snm.State = EfiSimpleNetworkInitialized;
- gBS->RestoreTPL (OldTpl);
- return EFI_SUCCESS;
-
-ReleaseTxAux:
- VirtioNetShutdownTx (Dev);
-
-AbortDevice:
- Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, 0);
-
-ReleaseTxRing:
- VirtioRingUninit (&Dev->TxRing);
-
-ReleaseRxRing:
- VirtioRingUninit (&Dev->RxRing);
-
-DeviceFailed:
- //
- // restore device status invariant for the EfiSimpleNetworkStarted state
- //
- Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, 0);
-
-InitFailed:
- gBS->RestoreTPL (OldTpl);
- return Status;
-}