304 lines
8.3 KiB
C
304 lines
8.3 KiB
C
|
/** @file
|
||
|
|
||
|
Helper functions used by at least two Simple Network Protocol methods.
|
||
|
|
||
|
Copyright (C) 2013, Red Hat, Inc.
|
||
|
|
||
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||
|
|
||
|
**/
|
||
|
|
||
|
#include <Library/MemoryAllocationLib.h>
|
||
|
|
||
|
#include "VirtioNet.h"
|
||
|
|
||
|
//
|
||
|
// The user structure for the ordered collection that will track the mapping
|
||
|
// info of the packets queued in TxRing
|
||
|
//
|
||
|
typedef struct {
|
||
|
VOID *Buffer;
|
||
|
EFI_PHYSICAL_ADDRESS DeviceAddress; // lookup key for reverse mapping
|
||
|
VOID *BufMap;
|
||
|
} TX_BUF_MAP_INFO;
|
||
|
|
||
|
/**
|
||
|
Release RX and TX resources on the boundary of the
|
||
|
EfiSimpleNetworkInitialized state.
|
||
|
|
||
|
These functions contribute to rolling back a partial, failed initialization
|
||
|
of the virtio-net SNP driver instance, or to shutting down a fully
|
||
|
initialized, running instance.
|
||
|
|
||
|
They are only callable by the VirtioNetInitialize() and the
|
||
|
VirtioNetShutdown() SNP methods. See the state diagram in "VirtioNet.h".
|
||
|
|
||
|
@param[in,out] Dev The VNET_DEV driver instance being shut down, or whose
|
||
|
partial, failed initialization is being rolled back.
|
||
|
*/
|
||
|
|
||
|
VOID
|
||
|
EFIAPI
|
||
|
VirtioNetShutdownRx (
|
||
|
IN OUT VNET_DEV *Dev
|
||
|
)
|
||
|
{
|
||
|
Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, Dev->RxBufMap);
|
||
|
Dev->VirtIo->FreeSharedPages (
|
||
|
Dev->VirtIo,
|
||
|
Dev->RxBufNrPages,
|
||
|
Dev->RxBuf
|
||
|
);
|
||
|
}
|
||
|
|
||
|
|
||
|
VOID
|
||
|
EFIAPI
|
||
|
VirtioNetShutdownTx (
|
||
|
IN OUT VNET_DEV *Dev
|
||
|
)
|
||
|
{
|
||
|
ORDERED_COLLECTION_ENTRY *Entry, *Entry2;
|
||
|
TX_BUF_MAP_INFO *TxBufMapInfo;
|
||
|
VOID *UserStruct;
|
||
|
|
||
|
Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, Dev->TxSharedReqMap);
|
||
|
Dev->VirtIo->FreeSharedPages (
|
||
|
Dev->VirtIo,
|
||
|
EFI_SIZE_TO_PAGES (sizeof *(Dev->TxSharedReq)),
|
||
|
Dev->TxSharedReq
|
||
|
);
|
||
|
|
||
|
for (Entry = OrderedCollectionMin (Dev->TxBufCollection);
|
||
|
Entry != NULL;
|
||
|
Entry = Entry2) {
|
||
|
Entry2 = OrderedCollectionNext (Entry);
|
||
|
OrderedCollectionDelete (Dev->TxBufCollection, Entry, &UserStruct);
|
||
|
TxBufMapInfo = UserStruct;
|
||
|
Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, TxBufMapInfo->BufMap);
|
||
|
FreePool (TxBufMapInfo);
|
||
|
}
|
||
|
OrderedCollectionUninit (Dev->TxBufCollection);
|
||
|
|
||
|
FreePool (Dev->TxFreeStack);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
Release TX and RX VRING resources.
|
||
|
|
||
|
@param[in,out] Dev The VNET_DEV driver instance which was using
|
||
|
the ring.
|
||
|
@param[in,out] Ring The virtio ring to clean up.
|
||
|
@param[in] RingMap A token return from the VirtioRingMap()
|
||
|
*/
|
||
|
VOID
|
||
|
EFIAPI
|
||
|
VirtioNetUninitRing (
|
||
|
IN OUT VNET_DEV *Dev,
|
||
|
IN OUT VRING *Ring,
|
||
|
IN VOID *RingMap
|
||
|
)
|
||
|
{
|
||
|
Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, RingMap);
|
||
|
VirtioRingUninit (Dev->VirtIo, Ring);
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
Map Caller-supplied TxBuf buffer to the device-mapped address
|
||
|
|
||
|
@param[in] Dev The VNET_DEV driver instance which wants to
|
||
|
map the Tx packet.
|
||
|
@param[in] Buffer The system physical address of TxBuf
|
||
|
@param[in] NumberOfBytes Number of bytes to map
|
||
|
@param[out] DeviceAddress The resulting device address for the bus
|
||
|
master access.
|
||
|
|
||
|
@retval EFI_OUT_OF_RESOURCES The request could not be completed due to
|
||
|
a lack of resources.
|
||
|
@return Status codes from
|
||
|
VirtioMapAllBytesInSharedBuffer()
|
||
|
@retval EFI_SUCCESS Caller-supplied buffer is succesfully mapped.
|
||
|
*/
|
||
|
EFI_STATUS
|
||
|
EFIAPI
|
||
|
VirtioNetMapTxBuf (
|
||
|
IN VNET_DEV *Dev,
|
||
|
IN VOID *Buffer,
|
||
|
IN UINTN NumberOfBytes,
|
||
|
OUT EFI_PHYSICAL_ADDRESS *DeviceAddress
|
||
|
)
|
||
|
{
|
||
|
EFI_STATUS Status;
|
||
|
TX_BUF_MAP_INFO *TxBufMapInfo;
|
||
|
EFI_PHYSICAL_ADDRESS Address;
|
||
|
VOID *Mapping;
|
||
|
|
||
|
TxBufMapInfo = AllocatePool (sizeof (*TxBufMapInfo));
|
||
|
if (TxBufMapInfo == NULL) {
|
||
|
return EFI_OUT_OF_RESOURCES;
|
||
|
}
|
||
|
|
||
|
Status = VirtioMapAllBytesInSharedBuffer (
|
||
|
Dev->VirtIo,
|
||
|
VirtioOperationBusMasterRead,
|
||
|
Buffer,
|
||
|
NumberOfBytes,
|
||
|
&Address,
|
||
|
&Mapping
|
||
|
);
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
goto FreeTxBufMapInfo;
|
||
|
}
|
||
|
|
||
|
TxBufMapInfo->Buffer = Buffer;
|
||
|
TxBufMapInfo->DeviceAddress = Address;
|
||
|
TxBufMapInfo->BufMap = Mapping;
|
||
|
|
||
|
Status = OrderedCollectionInsert (
|
||
|
Dev->TxBufCollection,
|
||
|
NULL,
|
||
|
TxBufMapInfo
|
||
|
);
|
||
|
switch (Status) {
|
||
|
case EFI_OUT_OF_RESOURCES:
|
||
|
goto UnmapTxBuf;
|
||
|
case EFI_ALREADY_STARTED:
|
||
|
//
|
||
|
// This should never happen: it implies
|
||
|
//
|
||
|
// - an identity-mapping VIRTIO_DEVICE_PROTOCOL.MapSharedBuffer()
|
||
|
// implementation -- which is fine,
|
||
|
//
|
||
|
// - and an SNP client that queues multiple instances of the exact same
|
||
|
// buffer address with SNP.Transmit() -- which is undefined behavior,
|
||
|
// based on the TxBuf language in UEFI-2.7,
|
||
|
// EFI_SIMPLE_NETWORK.GetStatus().
|
||
|
//
|
||
|
ASSERT (FALSE);
|
||
|
Status = EFI_INVALID_PARAMETER;
|
||
|
goto UnmapTxBuf;
|
||
|
default:
|
||
|
ASSERT_EFI_ERROR (Status);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
*DeviceAddress = Address;
|
||
|
return EFI_SUCCESS;
|
||
|
|
||
|
UnmapTxBuf:
|
||
|
Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, Mapping);
|
||
|
|
||
|
FreeTxBufMapInfo:
|
||
|
FreePool (TxBufMapInfo);
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
Unmap (aka reverse mapping) device mapped TxBuf buffer to the system
|
||
|
physical address
|
||
|
|
||
|
@param[in] Dev The VNET_DEV driver instance which wants to
|
||
|
reverse- and unmap the Tx packet.
|
||
|
@param[out] Buffer The system physical address of TxBuf
|
||
|
@param[in] DeviceAddress The device address for the TxBuf
|
||
|
|
||
|
@retval EFI_INVALID_PARAMETER The DeviceAddress is not mapped
|
||
|
@retval EFI_SUCCESS The TxBuf at DeviceAddress has been unmapped,
|
||
|
and Buffer has been set to TxBuf's system
|
||
|
physical address.
|
||
|
|
||
|
*/
|
||
|
EFI_STATUS
|
||
|
EFIAPI
|
||
|
VirtioNetUnmapTxBuf (
|
||
|
IN VNET_DEV *Dev,
|
||
|
OUT VOID **Buffer,
|
||
|
IN EFI_PHYSICAL_ADDRESS DeviceAddress
|
||
|
)
|
||
|
{
|
||
|
ORDERED_COLLECTION_ENTRY *Entry;
|
||
|
TX_BUF_MAP_INFO *TxBufMapInfo;
|
||
|
VOID *UserStruct;
|
||
|
|
||
|
Entry = OrderedCollectionFind (Dev->TxBufCollection, &DeviceAddress);
|
||
|
if (Entry == NULL) {
|
||
|
return EFI_INVALID_PARAMETER;
|
||
|
}
|
||
|
|
||
|
OrderedCollectionDelete (Dev->TxBufCollection, Entry, &UserStruct);
|
||
|
|
||
|
TxBufMapInfo = UserStruct;
|
||
|
|
||
|
*Buffer = TxBufMapInfo->Buffer;
|
||
|
Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, TxBufMapInfo->BufMap);
|
||
|
FreePool (TxBufMapInfo);
|
||
|
|
||
|
return EFI_SUCCESS;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
Comparator function for two TX_BUF_MAP_INFO objects.
|
||
|
|
||
|
@param[in] UserStruct1 Pointer to the first TX_BUF_MAP_INFO object.
|
||
|
|
||
|
@param[in] UserStruct2 Pointer to the second TX_BUF_MAP_INFO object.
|
||
|
|
||
|
@retval <0 If UserStruct1 compares less than UserStruct2.
|
||
|
|
||
|
@retval 0 If UserStruct1 compares equal to UserStruct2.
|
||
|
|
||
|
@retval >0 If UserStruct1 compares greater than UserStruct2.
|
||
|
*/
|
||
|
INTN
|
||
|
EFIAPI
|
||
|
VirtioNetTxBufMapInfoCompare (
|
||
|
IN CONST VOID *UserStruct1,
|
||
|
IN CONST VOID *UserStruct2
|
||
|
)
|
||
|
{
|
||
|
CONST TX_BUF_MAP_INFO *MapInfo1;
|
||
|
CONST TX_BUF_MAP_INFO *MapInfo2;
|
||
|
|
||
|
MapInfo1 = UserStruct1;
|
||
|
MapInfo2 = UserStruct2;
|
||
|
|
||
|
return MapInfo1->DeviceAddress < MapInfo2->DeviceAddress ? -1 :
|
||
|
MapInfo1->DeviceAddress > MapInfo2->DeviceAddress ? 1 :
|
||
|
0;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
Compare a standalone DeviceAddress against a TX_BUF_MAP_INFO object
|
||
|
containing an embedded DeviceAddress.
|
||
|
|
||
|
@param[in] StandaloneKey Pointer to DeviceAddress, which has type
|
||
|
EFI_PHYSICAL_ADDRESS.
|
||
|
|
||
|
@param[in] UserStruct Pointer to the TX_BUF_MAP_INFO object with the
|
||
|
embedded DeviceAddress.
|
||
|
|
||
|
@retval <0 If StandaloneKey compares less than UserStruct's key.
|
||
|
|
||
|
@retval 0 If StandaloneKey compares equal to UserStruct's key.
|
||
|
|
||
|
@retval >0 If StandaloneKey compares greater than UserStruct's key.
|
||
|
**/
|
||
|
INTN
|
||
|
EFIAPI
|
||
|
VirtioNetTxBufDeviceAddressCompare (
|
||
|
IN CONST VOID *StandaloneKey,
|
||
|
IN CONST VOID *UserStruct
|
||
|
)
|
||
|
{
|
||
|
CONST EFI_PHYSICAL_ADDRESS *DeviceAddress;
|
||
|
CONST TX_BUF_MAP_INFO *MapInfo;
|
||
|
|
||
|
DeviceAddress = StandaloneKey;
|
||
|
MapInfo = UserStruct;
|
||
|
|
||
|
return *DeviceAddress < MapInfo->DeviceAddress ? -1 :
|
||
|
*DeviceAddress > MapInfo->DeviceAddress ? 1 :
|
||
|
0;
|
||
|
}
|