SnpSharedHelpers.c 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  1. /** @file
  2. Helper functions used by at least two Simple Network Protocol methods.
  3. Copyright (C) 2013, Red Hat, Inc.
  4. SPDX-License-Identifier: BSD-2-Clause-Patent
  5. **/
  6. #include <Library/MemoryAllocationLib.h>
  7. #include "VirtioNet.h"
  8. //
  9. // The user structure for the ordered collection that will track the mapping
  10. // info of the packets queued in TxRing
  11. //
  12. typedef struct {
  13. VOID *Buffer;
  14. EFI_PHYSICAL_ADDRESS DeviceAddress; // lookup key for reverse mapping
  15. VOID *BufMap;
  16. } TX_BUF_MAP_INFO;
  17. /**
  18. Release RX and TX resources on the boundary of the
  19. EfiSimpleNetworkInitialized state.
  20. These functions contribute to rolling back a partial, failed initialization
  21. of the virtio-net SNP driver instance, or to shutting down a fully
  22. initialized, running instance.
  23. They are only callable by the VirtioNetInitialize() and the
  24. VirtioNetShutdown() SNP methods. See the state diagram in "VirtioNet.h".
  25. @param[in,out] Dev The VNET_DEV driver instance being shut down, or whose
  26. partial, failed initialization is being rolled back.
  27. */
  28. VOID
  29. EFIAPI
  30. VirtioNetShutdownRx (
  31. IN OUT VNET_DEV *Dev
  32. )
  33. {
  34. Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, Dev->RxBufMap);
  35. Dev->VirtIo->FreeSharedPages (
  36. Dev->VirtIo,
  37. Dev->RxBufNrPages,
  38. Dev->RxBuf
  39. );
  40. }
  41. VOID
  42. EFIAPI
  43. VirtioNetShutdownTx (
  44. IN OUT VNET_DEV *Dev
  45. )
  46. {
  47. ORDERED_COLLECTION_ENTRY *Entry, *Entry2;
  48. TX_BUF_MAP_INFO *TxBufMapInfo;
  49. VOID *UserStruct;
  50. Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, Dev->TxSharedReqMap);
  51. Dev->VirtIo->FreeSharedPages (
  52. Dev->VirtIo,
  53. EFI_SIZE_TO_PAGES (sizeof *(Dev->TxSharedReq)),
  54. Dev->TxSharedReq
  55. );
  56. for (Entry = OrderedCollectionMin (Dev->TxBufCollection);
  57. Entry != NULL;
  58. Entry = Entry2)
  59. {
  60. Entry2 = OrderedCollectionNext (Entry);
  61. OrderedCollectionDelete (Dev->TxBufCollection, Entry, &UserStruct);
  62. TxBufMapInfo = UserStruct;
  63. Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, TxBufMapInfo->BufMap);
  64. FreePool (TxBufMapInfo);
  65. }
  66. OrderedCollectionUninit (Dev->TxBufCollection);
  67. FreePool (Dev->TxFreeStack);
  68. }
  69. /**
  70. Release TX and RX VRING resources.
  71. @param[in,out] Dev The VNET_DEV driver instance which was using
  72. the ring.
  73. @param[in,out] Ring The virtio ring to clean up.
  74. @param[in] RingMap A token return from the VirtioRingMap()
  75. */
  76. VOID
  77. EFIAPI
  78. VirtioNetUninitRing (
  79. IN OUT VNET_DEV *Dev,
  80. IN OUT VRING *Ring,
  81. IN VOID *RingMap
  82. )
  83. {
  84. Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, RingMap);
  85. VirtioRingUninit (Dev->VirtIo, Ring);
  86. }
  87. /**
  88. Map Caller-supplied TxBuf buffer to the device-mapped address
  89. @param[in] Dev The VNET_DEV driver instance which wants to
  90. map the Tx packet.
  91. @param[in] Buffer The system physical address of TxBuf
  92. @param[in] NumberOfBytes Number of bytes to map
  93. @param[out] DeviceAddress The resulting device address for the bus
  94. master access.
  95. @retval EFI_OUT_OF_RESOURCES The request could not be completed due to
  96. a lack of resources.
  97. @return Status codes from
  98. VirtioMapAllBytesInSharedBuffer()
  99. @retval EFI_SUCCESS Caller-supplied buffer is successfully mapped.
  100. */
  101. EFI_STATUS
  102. EFIAPI
  103. VirtioNetMapTxBuf (
  104. IN VNET_DEV *Dev,
  105. IN VOID *Buffer,
  106. IN UINTN NumberOfBytes,
  107. OUT EFI_PHYSICAL_ADDRESS *DeviceAddress
  108. )
  109. {
  110. EFI_STATUS Status;
  111. TX_BUF_MAP_INFO *TxBufMapInfo;
  112. EFI_PHYSICAL_ADDRESS Address;
  113. VOID *Mapping;
  114. TxBufMapInfo = AllocatePool (sizeof (*TxBufMapInfo));
  115. if (TxBufMapInfo == NULL) {
  116. return EFI_OUT_OF_RESOURCES;
  117. }
  118. Status = VirtioMapAllBytesInSharedBuffer (
  119. Dev->VirtIo,
  120. VirtioOperationBusMasterRead,
  121. Buffer,
  122. NumberOfBytes,
  123. &Address,
  124. &Mapping
  125. );
  126. if (EFI_ERROR (Status)) {
  127. goto FreeTxBufMapInfo;
  128. }
  129. TxBufMapInfo->Buffer = Buffer;
  130. TxBufMapInfo->DeviceAddress = Address;
  131. TxBufMapInfo->BufMap = Mapping;
  132. Status = OrderedCollectionInsert (
  133. Dev->TxBufCollection,
  134. NULL,
  135. TxBufMapInfo
  136. );
  137. switch (Status) {
  138. case EFI_OUT_OF_RESOURCES:
  139. goto UnmapTxBuf;
  140. case EFI_ALREADY_STARTED:
  141. //
  142. // This should never happen: it implies
  143. //
  144. // - an identity-mapping VIRTIO_DEVICE_PROTOCOL.MapSharedBuffer()
  145. // implementation -- which is fine,
  146. //
  147. // - and an SNP client that queues multiple instances of the exact same
  148. // buffer address with SNP.Transmit() -- which is undefined behavior,
  149. // based on the TxBuf language in UEFI-2.7,
  150. // EFI_SIMPLE_NETWORK.GetStatus().
  151. //
  152. ASSERT (FALSE);
  153. Status = EFI_INVALID_PARAMETER;
  154. goto UnmapTxBuf;
  155. default:
  156. ASSERT_EFI_ERROR (Status);
  157. break;
  158. }
  159. *DeviceAddress = Address;
  160. return EFI_SUCCESS;
  161. UnmapTxBuf:
  162. Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, Mapping);
  163. FreeTxBufMapInfo:
  164. FreePool (TxBufMapInfo);
  165. return Status;
  166. }
  167. /**
  168. Unmap (aka reverse mapping) device mapped TxBuf buffer to the system
  169. physical address
  170. @param[in] Dev The VNET_DEV driver instance which wants to
  171. reverse- and unmap the Tx packet.
  172. @param[out] Buffer The system physical address of TxBuf
  173. @param[in] DeviceAddress The device address for the TxBuf
  174. @retval EFI_INVALID_PARAMETER The DeviceAddress is not mapped
  175. @retval EFI_SUCCESS The TxBuf at DeviceAddress has been unmapped,
  176. and Buffer has been set to TxBuf's system
  177. physical address.
  178. */
  179. EFI_STATUS
  180. EFIAPI
  181. VirtioNetUnmapTxBuf (
  182. IN VNET_DEV *Dev,
  183. OUT VOID **Buffer,
  184. IN EFI_PHYSICAL_ADDRESS DeviceAddress
  185. )
  186. {
  187. ORDERED_COLLECTION_ENTRY *Entry;
  188. TX_BUF_MAP_INFO *TxBufMapInfo;
  189. VOID *UserStruct;
  190. Entry = OrderedCollectionFind (Dev->TxBufCollection, &DeviceAddress);
  191. if (Entry == NULL) {
  192. return EFI_INVALID_PARAMETER;
  193. }
  194. OrderedCollectionDelete (Dev->TxBufCollection, Entry, &UserStruct);
  195. TxBufMapInfo = UserStruct;
  196. *Buffer = TxBufMapInfo->Buffer;
  197. Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, TxBufMapInfo->BufMap);
  198. FreePool (TxBufMapInfo);
  199. return EFI_SUCCESS;
  200. }
  201. /**
  202. Comparator function for two TX_BUF_MAP_INFO objects.
  203. @param[in] UserStruct1 Pointer to the first TX_BUF_MAP_INFO object.
  204. @param[in] UserStruct2 Pointer to the second TX_BUF_MAP_INFO object.
  205. @retval <0 If UserStruct1 compares less than UserStruct2.
  206. @retval 0 If UserStruct1 compares equal to UserStruct2.
  207. @retval >0 If UserStruct1 compares greater than UserStruct2.
  208. */
  209. INTN
  210. EFIAPI
  211. VirtioNetTxBufMapInfoCompare (
  212. IN CONST VOID *UserStruct1,
  213. IN CONST VOID *UserStruct2
  214. )
  215. {
  216. CONST TX_BUF_MAP_INFO *MapInfo1;
  217. CONST TX_BUF_MAP_INFO *MapInfo2;
  218. MapInfo1 = UserStruct1;
  219. MapInfo2 = UserStruct2;
  220. return MapInfo1->DeviceAddress < MapInfo2->DeviceAddress ? -1 :
  221. MapInfo1->DeviceAddress > MapInfo2->DeviceAddress ? 1 :
  222. 0;
  223. }
  224. /**
  225. Compare a standalone DeviceAddress against a TX_BUF_MAP_INFO object
  226. containing an embedded DeviceAddress.
  227. @param[in] StandaloneKey Pointer to DeviceAddress, which has type
  228. EFI_PHYSICAL_ADDRESS.
  229. @param[in] UserStruct Pointer to the TX_BUF_MAP_INFO object with the
  230. embedded DeviceAddress.
  231. @retval <0 If StandaloneKey compares less than UserStruct's key.
  232. @retval 0 If StandaloneKey compares equal to UserStruct's key.
  233. @retval >0 If StandaloneKey compares greater than UserStruct's key.
  234. **/
  235. INTN
  236. EFIAPI
  237. VirtioNetTxBufDeviceAddressCompare (
  238. IN CONST VOID *StandaloneKey,
  239. IN CONST VOID *UserStruct
  240. )
  241. {
  242. CONST EFI_PHYSICAL_ADDRESS *DeviceAddress;
  243. CONST TX_BUF_MAP_INFO *MapInfo;
  244. DeviceAddress = StandaloneKey;
  245. MapInfo = UserStruct;
  246. return *DeviceAddress < MapInfo->DeviceAddress ? -1 :
  247. *DeviceAddress > MapInfo->DeviceAddress ? 1 :
  248. 0;
  249. }