]> git.proxmox.com Git - mirror_edk2.git/blame - OvmfPkg/VirtioNetDxe/SnpTransmit.c
OvmfPkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / OvmfPkg / VirtioNetDxe / SnpTransmit.c
CommitLineData
b6dfc654
LE
1/** @file\r
2\r
3 Implementation of the SNP.Transmit() function and its private helpers if any.\r
4\r
5 Copyright (C) 2013, Red Hat, Inc.\r
8258c4e6 6 Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>\r
b6dfc654 7\r
b26f0cf9 8 SPDX-License-Identifier: BSD-2-Clause-Patent\r
b6dfc654
LE
9\r
10**/\r
11\r
12#include <Library/BaseLib.h>\r
13#include <Library/BaseMemoryLib.h>\r
14#include <Library/UefiBootServicesTableLib.h>\r
15\r
16#include "VirtioNet.h"\r
17\r
18/**\r
19 Places a packet in the transmit queue of a network interface.\r
20\r
21 @param This The protocol instance pointer.\r
22 @param HeaderSize The size, in bytes, of the media header to be filled in by\r
23 the Transmit() function. If HeaderSize is non-zero, then\r
24 it must be equal to This->Mode->MediaHeaderSize and the\r
25 DestAddr and Protocol parameters must not be NULL.\r
26 @param BufferSize The size, in bytes, of the entire packet (media header and\r
27 data) to be transmitted through the network interface.\r
28 @param Buffer A pointer to the packet (media header followed by data) to\r
29 be transmitted. This parameter cannot be NULL. If\r
30 HeaderSize is zero, then the media header in Buffer must\r
31 already be filled in by the caller. If HeaderSize is\r
32 non-zero, then the media header will be filled in by the\r
33 Transmit() function.\r
34 @param SrcAddr The source HW MAC address. If HeaderSize is zero, then\r
35 this parameter is ignored. If HeaderSize is non-zero and\r
36 SrcAddr is NULL, then This->Mode->CurrentAddress is used\r
37 for the source HW MAC address.\r
38 @param DestAddr The destination HW MAC address. If HeaderSize is zero,\r
39 then this parameter is ignored.\r
40 @param Protocol The type of header to build. If HeaderSize is zero, then\r
41 this parameter is ignored. See RFC 1700, section "Ether\r
42 Types", for examples.\r
43\r
44 @retval EFI_SUCCESS The packet was placed on the transmit queue.\r
45 @retval EFI_NOT_STARTED The network interface has not been started.\r
46 @retval EFI_NOT_READY The network interface is too busy to accept\r
47 this transmit request.\r
48 @retval EFI_BUFFER_TOO_SMALL The BufferSize parameter is too small.\r
49 @retval EFI_INVALID_PARAMETER One or more of the parameters has an\r
50 unsupported value.\r
51 @retval EFI_DEVICE_ERROR The command could not be sent to the network\r
52 interface.\r
53 @retval EFI_UNSUPPORTED This function is not supported by the network\r
54 interface.\r
55\r
56**/\r
57\r
58EFI_STATUS\r
59EFIAPI\r
60VirtioNetTransmit (\r
61 IN EFI_SIMPLE_NETWORK_PROTOCOL *This,\r
62 IN UINTN HeaderSize,\r
63 IN UINTN BufferSize,\r
64 IN /* +OUT! */ VOID *Buffer,\r
65 IN EFI_MAC_ADDRESS *SrcAddr OPTIONAL,\r
66 IN EFI_MAC_ADDRESS *DestAddr OPTIONAL,\r
67 IN UINT16 *Protocol OPTIONAL\r
68 )\r
69{\r
8fa54a8a
BS
70 VNET_DEV *Dev;\r
71 EFI_TPL OldTpl;\r
72 EFI_STATUS Status;\r
73 UINT16 DescIdx;\r
74 UINT16 AvailIdx;\r
75 EFI_PHYSICAL_ADDRESS DeviceAddress;\r
b6dfc654
LE
76\r
77 if (This == NULL || BufferSize == 0 || Buffer == NULL) {\r
78 return EFI_INVALID_PARAMETER;\r
79 }\r
80\r
81 Dev = VIRTIO_NET_FROM_SNP (This);\r
82 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
83 switch (Dev->Snm.State) {\r
84 case EfiSimpleNetworkStopped:\r
85 Status = EFI_NOT_STARTED;\r
86 goto Exit;\r
87 case EfiSimpleNetworkStarted:\r
88 Status = EFI_DEVICE_ERROR;\r
89 goto Exit;\r
90 default:\r
91 break;\r
92 }\r
93\r
94 if (BufferSize < Dev->Snm.MediaHeaderSize) {\r
95 Status = EFI_BUFFER_TOO_SMALL;\r
96 goto Exit;\r
97 }\r
98 if (BufferSize > Dev->Snm.MediaHeaderSize + Dev->Snm.MaxPacketSize) {\r
99 Status = EFI_INVALID_PARAMETER;\r
100 goto Exit;\r
101 }\r
102\r
103 //\r
104 // check if we have room for transmission\r
105 //\r
106 ASSERT (Dev->TxCurPending <= Dev->TxMaxPending);\r
107 if (Dev->TxCurPending == Dev->TxMaxPending) {\r
108 Status = EFI_NOT_READY;\r
109 goto Exit;\r
110 }\r
111\r
112 //\r
113 // the caller may want us to fill in the media header:\r
114 // dst MAC, src MAC, Ethertype\r
115 //\r
116 if (HeaderSize != 0) {\r
117 UINT8 *Ptr;\r
118\r
119 if (HeaderSize != Dev->Snm.MediaHeaderSize ||\r
120 DestAddr == NULL || Protocol == NULL) {\r
121 Status = EFI_INVALID_PARAMETER;\r
122 goto Exit;\r
123 }\r
124 Ptr = Buffer;\r
56f65ed8 125 ASSERT (SIZE_OF_VNET (Mac) <= sizeof (EFI_MAC_ADDRESS));\r
b6dfc654 126\r
56f65ed8
OM
127 CopyMem (Ptr, DestAddr, SIZE_OF_VNET (Mac));\r
128 Ptr += SIZE_OF_VNET (Mac);\r
b6dfc654
LE
129\r
130 CopyMem (Ptr,\r
131 (SrcAddr == NULL) ? &Dev->Snm.CurrentAddress : SrcAddr,\r
56f65ed8
OM
132 SIZE_OF_VNET (Mac));\r
133 Ptr += SIZE_OF_VNET (Mac);\r
b6dfc654
LE
134\r
135 *Ptr++ = (UINT8) (*Protocol >> 8);\r
136 *Ptr++ = (UINT8) *Protocol;\r
137\r
8258c4e6 138 ASSERT ((UINTN) (Ptr - (UINT8 *) Buffer) == Dev->Snm.MediaHeaderSize);\r
b6dfc654
LE
139 }\r
140\r
8fa54a8a
BS
141 //\r
142 // Map the transmit buffer system physical address to device address.\r
143 //\r
144 Status = VirtioNetMapTxBuf (\r
145 Dev,\r
146 Buffer,\r
147 BufferSize,\r
148 &DeviceAddress\r
149 );\r
150 if (EFI_ERROR (Status)) {\r
151 Status = EFI_DEVICE_ERROR;\r
152 goto Exit;\r
153 }\r
154\r
b6dfc654
LE
155 //\r
156 // virtio-0.9.5, 2.4.1 Supplying Buffers to The Device\r
157 //\r
158 DescIdx = Dev->TxFreeStack[Dev->TxCurPending++];\r
8fa54a8a 159 Dev->TxRing.Desc[DescIdx + 1].Addr = DeviceAddress;\r
b6dfc654
LE
160 Dev->TxRing.Desc[DescIdx + 1].Len = (UINT32) BufferSize;\r
161\r
162 //\r
163 // the available index is never written by the host, we can read it back\r
164 // without a barrier\r
165 //\r
166 AvailIdx = *Dev->TxRing.Avail.Idx;\r
167 Dev->TxRing.Avail.Ring[AvailIdx++ % Dev->TxRing.QueueSize] = DescIdx;\r
168\r
169 MemoryFence ();\r
170 *Dev->TxRing.Avail.Idx = AvailIdx;\r
171\r
172 MemoryFence ();\r
56f65ed8 173 Status = Dev->VirtIo->SetQueueNotify (Dev->VirtIo, VIRTIO_NET_Q_TX);\r
b6dfc654
LE
174\r
175Exit:\r
176 gBS->RestoreTPL (OldTpl);\r
177 return Status;\r
178}\r