TianoCore EDK2 master
Loading...
Searching...
No Matches
SnpReceive.c
Go to the documentation of this file.
1
12#include <Library/BaseLib.h>
15
16#include "VirtioNet.h"
17
56EFIAPI
59 OUT UINTN *HeaderSize OPTIONAL,
60 IN OUT UINTN *BufferSize,
61 OUT VOID *Buffer,
62 OUT EFI_MAC_ADDRESS *SrcAddr OPTIONAL,
63 OUT EFI_MAC_ADDRESS *DestAddr OPTIONAL,
64 OUT UINT16 *Protocol OPTIONAL
65 )
66{
67 VNET_DEV *Dev;
68 EFI_TPL OldTpl;
69 EFI_STATUS Status;
70 UINT16 RxCurUsed;
71 UINT16 UsedElemIdx;
72 UINT32 DescIdx;
73 UINT32 RxLen;
74 UINTN OrigBufferSize;
75 UINT8 *RxPtr;
76 UINT16 AvailIdx;
77 EFI_STATUS NotifyStatus;
78 UINTN RxBufOffset;
79
80 if ((This == NULL) || (BufferSize == NULL) || (Buffer == NULL)) {
81 return EFI_INVALID_PARAMETER;
82 }
83
84 Dev = VIRTIO_NET_FROM_SNP (This);
85 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
86 switch (Dev->Snm.State) {
87 case EfiSimpleNetworkStopped:
88 Status = EFI_NOT_STARTED;
89 goto Exit;
90 case EfiSimpleNetworkStarted:
91 Status = EFI_DEVICE_ERROR;
92 goto Exit;
93 default:
94 break;
95 }
96
97 //
98 // virtio-0.9.5, 2.4.2 Receiving Used Buffers From the Device
99 //
100 MemoryFence ();
101 RxCurUsed = *Dev->RxRing.Used.Idx;
102 MemoryFence ();
103
104 if (Dev->RxLastUsed == RxCurUsed) {
105 Status = EFI_NOT_READY;
106 goto Exit;
107 }
108
109 UsedElemIdx = Dev->RxLastUsed % Dev->RxRing.QueueSize;
110 DescIdx = Dev->RxRing.Used.UsedElem[UsedElemIdx].Id;
111 RxLen = Dev->RxRing.Used.UsedElem[UsedElemIdx].Len;
112
113 //
114 // the virtio-net request header must be complete; we skip it
115 //
116 ASSERT (RxLen >= Dev->RxRing.Desc[DescIdx].Len);
117 RxLen -= Dev->RxRing.Desc[DescIdx].Len;
118 //
119 // the host must not have filled in more data than requested
120 //
121 ASSERT (RxLen <= Dev->RxRing.Desc[DescIdx + 1].Len);
122
123 OrigBufferSize = *BufferSize;
124 *BufferSize = RxLen;
125
126 if (OrigBufferSize < RxLen) {
127 Status = EFI_BUFFER_TOO_SMALL;
128 goto Exit; // keep the packet
129 }
130
131 if (RxLen < Dev->Snm.MediaHeaderSize) {
132 Status = EFI_DEVICE_ERROR;
133 goto RecycleDesc; // drop useless short packet
134 }
135
136 if (HeaderSize != NULL) {
137 *HeaderSize = Dev->Snm.MediaHeaderSize;
138 }
139
140 RxBufOffset = (UINTN)(Dev->RxRing.Desc[DescIdx + 1].Addr -
141 Dev->RxBufDeviceBase);
142 RxPtr = Dev->RxBuf + RxBufOffset;
143 CopyMem (Buffer, RxPtr, RxLen);
144
145 if (DestAddr != NULL) {
146 CopyMem (DestAddr, RxPtr, SIZE_OF_VNET (Mac));
147 }
148
149 RxPtr += SIZE_OF_VNET (Mac);
150
151 if (SrcAddr != NULL) {
152 CopyMem (SrcAddr, RxPtr, SIZE_OF_VNET (Mac));
153 }
154
155 RxPtr += SIZE_OF_VNET (Mac);
156
157 if (Protocol != NULL) {
158 *Protocol = (UINT16)((RxPtr[0] << 8) | RxPtr[1]);
159 }
160
161 RxPtr += sizeof (UINT16);
162
163 Status = EFI_SUCCESS;
164
165RecycleDesc:
166 ++Dev->RxLastUsed;
167
168 //
169 // virtio-0.9.5, 2.4.1 Supplying Buffers to The Device
170 //
171 AvailIdx = *Dev->RxRing.Avail.Idx;
172 Dev->RxRing.Avail.Ring[AvailIdx++ % Dev->RxRing.QueueSize] =
173 (UINT16)DescIdx;
174
175 MemoryFence ();
176 *Dev->RxRing.Avail.Idx = AvailIdx;
177
178 MemoryFence ();
179 NotifyStatus = Dev->VirtIo->SetQueueNotify (Dev->VirtIo, VIRTIO_NET_Q_RX);
180 if (!EFI_ERROR (Status)) {
181 // earlier error takes precedence
182 Status = NotifyStatus;
183 }
184
185Exit:
186 gBS->RestoreTPL (OldTpl);
187 return Status;
188}
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
#define OUT
Definition: Base.h:284
EFI_STATUS EFIAPI VirtioNetReceive(IN EFI_SIMPLE_NETWORK_PROTOCOL *This, OUT UINTN *HeaderSize OPTIONAL, IN OUT UINTN *BufferSize, OUT VOID *Buffer, OUT EFI_MAC_ADDRESS *SrcAddr OPTIONAL, OUT EFI_MAC_ADDRESS *DestAddr OPTIONAL, OUT UINT16 *Protocol OPTIONAL)
Definition: SnpReceive.c:57
VOID EFIAPI Exit(IN EFI_STATUS Status)
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
UINTN EFI_TPL
Definition: UefiBaseType.h:41
#define EFI_SUCCESS
Definition: UefiBaseType.h:112
EFI_BOOT_SERVICES * gBS