TianoCore EDK2 master
Loading...
Searching...
No Matches
SnpTransmit.c
Go to the documentation of this file.
1
12#include <Library/BaseLib.h>
15
16#include "VirtioNet.h"
17
58EFIAPI
61 IN UINTN HeaderSize,
62 IN UINTN BufferSize,
63 IN /* +OUT! */ VOID *Buffer,
64 IN EFI_MAC_ADDRESS *SrcAddr OPTIONAL,
65 IN EFI_MAC_ADDRESS *DestAddr OPTIONAL,
66 IN UINT16 *Protocol OPTIONAL
67 )
68{
69 VNET_DEV *Dev;
70 EFI_TPL OldTpl;
71 EFI_STATUS Status;
72 UINT16 DescIdx;
73 UINT16 AvailIdx;
74 EFI_PHYSICAL_ADDRESS DeviceAddress;
75
76 if ((This == NULL) || (BufferSize == 0) || (Buffer == NULL)) {
77 return EFI_INVALID_PARAMETER;
78 }
79
80 Dev = VIRTIO_NET_FROM_SNP (This);
81 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
82 switch (Dev->Snm.State) {
83 case EfiSimpleNetworkStopped:
84 Status = EFI_NOT_STARTED;
85 goto Exit;
86 case EfiSimpleNetworkStarted:
87 Status = EFI_DEVICE_ERROR;
88 goto Exit;
89 default:
90 break;
91 }
92
93 if (BufferSize < Dev->Snm.MediaHeaderSize) {
94 Status = EFI_BUFFER_TOO_SMALL;
95 goto Exit;
96 }
97
98 if (BufferSize > Dev->Snm.MediaHeaderSize + Dev->Snm.MaxPacketSize) {
99 Status = EFI_INVALID_PARAMETER;
100 goto Exit;
101 }
102
103 //
104 // check if we have room for transmission
105 //
106 ASSERT (Dev->TxCurPending <= Dev->TxMaxPending);
107 if (Dev->TxCurPending == Dev->TxMaxPending) {
108 Status = EFI_NOT_READY;
109 goto Exit;
110 }
111
112 //
113 // the caller may want us to fill in the media header:
114 // dst MAC, src MAC, Ethertype
115 //
116 if (HeaderSize != 0) {
117 UINT8 *Ptr;
118
119 if ((HeaderSize != Dev->Snm.MediaHeaderSize) ||
120 (DestAddr == NULL) || (Protocol == NULL))
121 {
122 Status = EFI_INVALID_PARAMETER;
123 goto Exit;
124 }
125
126 Ptr = Buffer;
127 ASSERT (SIZE_OF_VNET (Mac) <= sizeof (EFI_MAC_ADDRESS));
128
129 CopyMem (Ptr, DestAddr, SIZE_OF_VNET (Mac));
130 Ptr += SIZE_OF_VNET (Mac);
131
132 CopyMem (
133 Ptr,
134 (SrcAddr == NULL) ? &Dev->Snm.CurrentAddress : SrcAddr,
135 SIZE_OF_VNET (Mac)
136 );
137 Ptr += SIZE_OF_VNET (Mac);
138
139 *Ptr++ = (UINT8)(*Protocol >> 8);
140 *Ptr++ = (UINT8)*Protocol;
141
142 ASSERT ((UINTN)(Ptr - (UINT8 *)Buffer) == Dev->Snm.MediaHeaderSize);
143 }
144
145 //
146 // Map the transmit buffer system physical address to device address.
147 //
148 Status = VirtioNetMapTxBuf (
149 Dev,
150 Buffer,
151 BufferSize,
152 &DeviceAddress
153 );
154 if (EFI_ERROR (Status)) {
155 Status = EFI_DEVICE_ERROR;
156 goto Exit;
157 }
158
159 //
160 // virtio-0.9.5, 2.4.1 Supplying Buffers to The Device
161 //
162 DescIdx = Dev->TxFreeStack[Dev->TxCurPending++];
163 Dev->TxRing.Desc[DescIdx + 1].Addr = DeviceAddress;
164 Dev->TxRing.Desc[DescIdx + 1].Len = (UINT32)BufferSize;
165
166 //
167 // the available index is never written by the host, we can read it back
168 // without a barrier
169 //
170 AvailIdx = *Dev->TxRing.Avail.Idx;
171 Dev->TxRing.Avail.Ring[AvailIdx++ % Dev->TxRing.QueueSize] = DescIdx;
172
173 MemoryFence ();
174 *Dev->TxRing.Avail.Idx = AvailIdx;
175
176 MemoryFence ();
177 Status = Dev->VirtIo->SetQueueNotify (Dev->VirtIo, VIRTIO_NET_Q_TX);
178
179Exit:
180 gBS->RestoreTPL (OldTpl);
181 return Status;
182}
UINT64 UINTN
VOID EFIAPI MemoryFence(VOID)
Definition: CpuBreakpoint.c:42
VOID *EFIAPI CopyMem(OUT VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
#define NULL
Definition: Base.h:319
#define IN
Definition: Base.h:279
EFI_STATUS EFIAPI VirtioNetMapTxBuf(IN VNET_DEV *Dev, IN VOID *Buffer, IN UINTN NumberOfBytes, OUT EFI_PHYSICAL_ADDRESS *DeviceAddress)
EFI_STATUS EFIAPI VirtioNetTransmit(IN EFI_SIMPLE_NETWORK_PROTOCOL *This, IN UINTN HeaderSize, IN UINTN BufferSize, IN VOID *Buffer, IN EFI_MAC_ADDRESS *SrcAddr OPTIONAL, IN EFI_MAC_ADDRESS *DestAddr OPTIONAL, IN UINT16 *Protocol OPTIONAL)
Definition: SnpTransmit.c:59
VOID EFIAPI Exit(IN EFI_STATUS Status)
UINT64 EFI_PHYSICAL_ADDRESS
Definition: UefiBaseType.h:50
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
UINTN EFI_TPL
Definition: UefiBaseType.h:41
EFI_BOOT_SERVICES * gBS
EFI_MAC_ADDRESS CurrentAddress