\r
#include "VirtioNet.h"\r
\r
+//\r
+// The user structure for the ordered collection that will track the mapping\r
+// info of the packets queued in TxRing\r
+//\r
+typedef struct {\r
+ VOID *Buffer;\r
+ EFI_PHYSICAL_ADDRESS DeviceAddress; // lookup key for reverse mapping\r
+ VOID *BufMap;\r
+} TX_BUF_MAP_INFO;\r
+\r
/**\r
Release RX and TX resources on the boundary of the\r
EfiSimpleNetworkInitialized state.\r
IN OUT VNET_DEV *Dev\r
)\r
{\r
+ ORDERED_COLLECTION_ENTRY *Entry, *Entry2;\r
+ TX_BUF_MAP_INFO *TxBufMapInfo;\r
+ VOID *UserStruct;\r
+\r
+ Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, Dev->TxSharedReqMap);\r
+ Dev->VirtIo->FreeSharedPages (\r
+ Dev->VirtIo,\r
+ EFI_SIZE_TO_PAGES (sizeof *(Dev->TxSharedReq)),\r
+ Dev->TxSharedReq\r
+ );\r
+\r
+ for (Entry = OrderedCollectionMin (Dev->TxBufCollection);\r
+ Entry != NULL;\r
+ Entry = Entry2) {\r
+ Entry2 = OrderedCollectionNext (Entry);\r
+ OrderedCollectionDelete (Dev->TxBufCollection, Entry, &UserStruct);\r
+ TxBufMapInfo = UserStruct;\r
+ Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, TxBufMapInfo->BufMap);\r
+ FreePool (TxBufMapInfo);\r
+ }\r
+ OrderedCollectionUninit (Dev->TxBufCollection);\r
+\r
FreePool (Dev->TxFreeStack);\r
}\r
\r
Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, RingMap);\r
VirtioRingUninit (Dev->VirtIo, Ring);\r
}\r
+\r
+\r
+/**\r
+ Map Caller-supplied TxBuf buffer to the device-mapped address\r
+\r
+ @param[in] Dev The VNET_DEV driver instance which wants to\r
+ map the Tx packet.\r
+ @param[in] Buffer The system physical address of TxBuf\r
+ @param[in] NumberOfBytes Number of bytes to map\r
+ @param[out] DeviceAddress The resulting device address for the bus\r
+ master access.\r
+\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to\r
+ a lack of resources.\r
+ @return Status codes from\r
+ VirtioMapAllBytesInSharedBuffer()\r
+ @retval EFI_SUCCESS Caller-supplied buffer is succesfully mapped.\r
+*/\r
+EFI_STATUS\r
+EFIAPI\r
+VirtioNetMapTxBuf (\r
+ IN VNET_DEV *Dev,\r
+ IN VOID *Buffer,\r
+ IN UINTN NumberOfBytes,\r
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ TX_BUF_MAP_INFO *TxBufMapInfo;\r
+ EFI_PHYSICAL_ADDRESS Address;\r
+ VOID *Mapping;\r
+\r
+ TxBufMapInfo = AllocatePool (sizeof (*TxBufMapInfo));\r
+ if (TxBufMapInfo == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ Status = VirtioMapAllBytesInSharedBuffer (\r
+ Dev->VirtIo,\r
+ VirtioOperationBusMasterRead,\r
+ Buffer,\r
+ NumberOfBytes,\r
+ &Address,\r
+ &Mapping\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto FreeTxBufMapInfo;\r
+ }\r
+\r
+ TxBufMapInfo->Buffer = Buffer;\r
+ TxBufMapInfo->DeviceAddress = Address;\r
+ TxBufMapInfo->BufMap = Mapping;\r
+\r
+ Status = OrderedCollectionInsert (\r
+ Dev->TxBufCollection,\r
+ NULL,\r
+ TxBufMapInfo\r
+ );\r
+ switch (Status) {\r
+ case EFI_OUT_OF_RESOURCES:\r
+ goto UnmapTxBuf;\r
+ case EFI_ALREADY_STARTED:\r
+ //\r
+ // This should never happen: it implies\r
+ //\r
+ // - an identity-mapping VIRTIO_DEVICE_PROTOCOL.MapSharedBuffer()\r
+ // implementation -- which is fine,\r
+ //\r
+ // - and an SNP client that queues multiple instances of the exact same\r
+ // buffer address with SNP.Transmit() -- which is undefined behavior,\r
+ // based on the TxBuf language in UEFI-2.7,\r
+ // EFI_SIMPLE_NETWORK.GetStatus().\r
+ //\r
+ ASSERT (FALSE);\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto UnmapTxBuf;\r
+ default:\r
+ ASSERT_EFI_ERROR (Status);\r
+ break;\r
+ }\r
+\r
+ *DeviceAddress = Address;\r
+ return EFI_SUCCESS;\r
+\r
+UnmapTxBuf:\r
+ Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, Mapping);\r
+\r
+FreeTxBufMapInfo:\r
+ FreePool (TxBufMapInfo);\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Unmap (aka reverse mapping) device mapped TxBuf buffer to the system\r
+ physical address\r
+\r
+ @param[in] Dev The VNET_DEV driver instance which wants to\r
+ reverse- and unmap the Tx packet.\r
+ @param[out] Buffer The system physical address of TxBuf\r
+ @param[in] DeviceAddress The device address for the TxBuf\r
+\r
+ @retval EFI_INVALID_PARAMETER The DeviceAddress is not mapped\r
+ @retval EFI_SUCCESS The TxBuf at DeviceAddress has been unmapped,\r
+ and Buffer has been set to TxBuf's system\r
+ physical address.\r
+\r
+*/\r
+EFI_STATUS\r
+EFIAPI\r
+VirtioNetUnmapTxBuf (\r
+ IN VNET_DEV *Dev,\r
+ OUT VOID **Buffer,\r
+ IN EFI_PHYSICAL_ADDRESS DeviceAddress\r
+ )\r
+{\r
+ ORDERED_COLLECTION_ENTRY *Entry;\r
+ TX_BUF_MAP_INFO *TxBufMapInfo;\r
+ VOID *UserStruct;\r
+\r
+ Entry = OrderedCollectionFind (Dev->TxBufCollection, &DeviceAddress);\r
+ if (Entry == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ OrderedCollectionDelete (Dev->TxBufCollection, Entry, &UserStruct);\r
+\r
+ TxBufMapInfo = UserStruct;\r
+\r
+ *Buffer = TxBufMapInfo->Buffer;\r
+ Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, TxBufMapInfo->BufMap);\r
+ FreePool (TxBufMapInfo);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Comparator function for two TX_BUF_MAP_INFO objects.\r
+\r
+ @param[in] UserStruct1 Pointer to the first TX_BUF_MAP_INFO object.\r
+\r
+ @param[in] UserStruct2 Pointer to the second TX_BUF_MAP_INFO object.\r
+\r
+ @retval <0 If UserStruct1 compares less than UserStruct2.\r
+\r
+ @retval 0 If UserStruct1 compares equal to UserStruct2.\r
+\r
+ @retval >0 If UserStruct1 compares greater than UserStruct2.\r
+*/\r
+INTN\r
+EFIAPI\r
+VirtioNetTxBufMapInfoCompare (\r
+ IN CONST VOID *UserStruct1,\r
+ IN CONST VOID *UserStruct2\r
+ )\r
+{\r
+ CONST TX_BUF_MAP_INFO *MapInfo1;\r
+ CONST TX_BUF_MAP_INFO *MapInfo2;\r
+\r
+ MapInfo1 = UserStruct1;\r
+ MapInfo2 = UserStruct2;\r
+\r
+ return MapInfo1->DeviceAddress < MapInfo2->DeviceAddress ? -1 :\r
+ MapInfo1->DeviceAddress > MapInfo2->DeviceAddress ? 1 :\r
+ 0;\r
+}\r
+\r
+/**\r
+ Compare a standalone DeviceAddress against a TX_BUF_MAP_INFO object\r
+ containing an embedded DeviceAddress.\r
+\r
+ @param[in] StandaloneKey Pointer to DeviceAddress, which has type\r
+ EFI_PHYSICAL_ADDRESS.\r
+\r
+ @param[in] UserStruct Pointer to the TX_BUF_MAP_INFO object with the\r
+ embedded DeviceAddress.\r
+\r
+ @retval <0 If StandaloneKey compares less than UserStruct's key.\r
+\r
+ @retval 0 If StandaloneKey compares equal to UserStruct's key.\r
+\r
+ @retval >0 If StandaloneKey compares greater than UserStruct's key.\r
+**/\r
+INTN\r
+EFIAPI\r
+VirtioNetTxBufDeviceAddressCompare (\r
+ IN CONST VOID *StandaloneKey,\r
+ IN CONST VOID *UserStruct\r
+ )\r
+{\r
+ CONST EFI_PHYSICAL_ADDRESS *DeviceAddress;\r
+ CONST TX_BUF_MAP_INFO *MapInfo;\r
+\r
+ DeviceAddress = StandaloneKey;\r
+ MapInfo = UserStruct;\r
+\r
+ return *DeviceAddress < MapInfo->DeviceAddress ? -1 :\r
+ *DeviceAddress > MapInfo->DeviceAddress ? 1 :\r
+ 0;\r
+}\r