VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/Firmware/VBoxPkg/E1kNetDxe/SnpInitialize.c

Last change on this file was 89503, checked in by vboxsync, 3 years ago

EFI/E1kNetDxe: Updates, the basic receive and transmit operations are functional and PXE booting seems to work with the limited testing done, include the driver in our image

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 10.3 KB
Line 
1/** @file
2
3 Implementation of the SNP.Initialize() function and its private helpers if
4 any.
5
6 Copyright (c) 2021, Oracle and/or its affiliates.
7 Copyright (c) 2017, AMD Inc, All rights reserved.
8 Copyright (C) 2013, Red Hat, Inc.
9 Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
10
11 SPDX-License-Identifier: BSD-2-Clause-Patent
12
13**/
14
15#include <Library/BaseLib.h>
16#include <Library/BaseMemoryLib.h>
17#include <Library/MemoryAllocationLib.h>
18#include <Library/UefiBootServicesTableLib.h>
19
20#include "E1kNet.h"
21
22/**
23 Set up static scaffolding for the E1kNetTransmit() and
24 E1kNetGetStatus() SNP methods.
25
26 This function may only be called by E1kNetInitialize().
27
28 @param[in,out] Dev The E1K_NET_DEV driver instance about to enter the
29 EfiSimpleNetworkInitialized state.
30
31 @retval EFI_OUT_OF_RESOURCES Failed to allocate the stack to track the heads
32 of free descriptor chains or failed to init
33 TxBufCollection.
34 @return Status codes from VIRTIO_DEVICE_PROTOCOL.
35 AllocateSharedPages() or
36 VirtioMapAllBytesInSharedBuffer()
37 @retval EFI_SUCCESS TX setup successful.
38*/
39
40STATIC
41EFI_STATUS
42EFIAPI
43E1kNetInitTx (
44 IN OUT E1K_NET_DEV *Dev
45 )
46{
47 UINTN TxRingSize;
48 EFI_STATUS Status;
49 EFI_PHYSICAL_ADDRESS DeviceAddress;
50 VOID *TxRingBuffer;
51
52 Dev->TxMaxPending = E1K_NET_MAX_PENDING;
53 Dev->TxCurPending = 0;
54 Dev->TxBufCollection = OrderedCollectionInit (
55 E1kNetTxBufMapInfoCompare,
56 E1kNetTxBufDeviceAddressCompare
57 );
58 if (Dev->TxBufCollection == NULL) {
59 Status = EFI_OUT_OF_RESOURCES;
60 goto Exit;
61 }
62
63 //
64 // Allocate TxRing header and map with BusMasterCommonBuffer so that it
65 // can be accessed equally by both processor and device.
66 //
67 TxRingSize = Dev->TxMaxPending * sizeof (*Dev->TxRing);
68 Status = Dev->PciIo->AllocateBuffer (
69 Dev->PciIo,
70 AllocateAnyPages,
71 EfiBootServicesData,
72 EFI_SIZE_TO_PAGES (TxRingSize),
73 &TxRingBuffer,
74 EFI_PCI_ATTRIBUTE_MEMORY_CACHED
75 );
76 if (EFI_ERROR (Status)) {
77 goto UninitTxBufCollection;
78 }
79
80 ZeroMem (TxRingBuffer, TxRingSize);
81
82 Status = Dev->PciIo->Map (
83 Dev->PciIo,
84 EfiPciIoOperationBusMasterCommonBuffer,
85 TxRingBuffer,
86 &TxRingSize,
87 &DeviceAddress,
88 &Dev->TxRingMap
89 );
90 if (EFI_ERROR (Status)) {
91 goto FreeTxRingBuffer;
92 }
93
94 Dev->TxRing = TxRingBuffer;
95 Dev->TdhLastSeen = 0;
96 Dev->TxLastUsed = 0;
97
98 // Program the transmit engine.
99 MemoryFence ();
100 E1kNetRegWrite32(Dev, E1K_REG_TDBAL, (UINT32)DeviceAddress);
101 E1kNetRegWrite32(Dev, E1K_REG_TDBAH, (UINT32)(RShiftU64 (DeviceAddress, 32)));
102 E1kNetRegWrite32(Dev, E1K_REG_TDLEN, (UINT32)TxRingSize);
103 E1kNetRegWrite32(Dev, E1K_REG_TDH, 0);
104 E1kNetRegWrite32(Dev, E1K_REG_TDT, 0);
105 E1kNetRegWrite32(Dev, E1K_REG_TCTL, E1K_REG_TCTL_EN | E1K_REG_TCTL_PSP);
106
107 return EFI_SUCCESS;
108
109FreeTxRingBuffer:
110 Dev->PciIo->FreeBuffer (
111 Dev->PciIo,
112 EFI_SIZE_TO_PAGES (TxRingSize),
113 TxRingBuffer
114 );
115
116UninitTxBufCollection:
117 OrderedCollectionUninit (Dev->TxBufCollection);
118
119Exit:
120 return Status;
121}
122
123
124/**
125 Set up static scaffolding for the E1kNetReceive() SNP method and enable
126 live device operation.
127
128 This function may only be called as E1kNetInitialize()'s final step.
129
130 @param[in,out] Dev The E1K_NET_DEV driver instance about to enter the
131 EfiSimpleNetworkInitialized state.
132
133 @return Status codes from VIRTIO_CFG_WRITE() or
134 VIRTIO_DEVICE_PROTOCOL.AllocateSharedPages or
135 VirtioMapAllBytesInSharedBuffer().
136 @retval EFI_SUCCESS RX setup successful. The device is live and may
137 already be writing to the receive area.
138*/
139
140STATIC
141EFI_STATUS
142EFIAPI
143E1kNetInitRx (
144 IN OUT E1K_NET_DEV *Dev
145 )
146{
147 EFI_STATUS Status;
148 UINTN RxBufSize;
149 UINTN PktIdx;
150 UINTN NumBytes;
151 EFI_PHYSICAL_ADDRESS RxBufDeviceAddress;
152 VOID *RxBuffer;
153
154 //
155 // For each incoming packet we must supply two buffers:
156 // - the recipient for the RX descriptor, plus
157 // - the recipient for the network data (which consists of Ethernet header
158 // and Ethernet payload) which is a 2KB buffer.
159 //
160 RxBufSize = sizeof(*Dev->RxRing) + 2048;
161
162 //
163 // The RxBuf is shared between guest and hypervisor, use
164 // AllocateSharedPages() to allocate this memory region and map it with
165 // BusMasterCommonBuffer so that it can be accessed by both guest and
166 // hypervisor.
167 //
168 NumBytes = E1K_NET_MAX_PENDING * RxBufSize;
169 Dev->RxBufNrPages = EFI_SIZE_TO_PAGES (NumBytes);
170 Status = Dev->PciIo->AllocateBuffer (
171 Dev->PciIo,
172 AllocateAnyPages,
173 EfiBootServicesData,
174 Dev->RxBufNrPages,
175 &RxBuffer,
176 EFI_PCI_ATTRIBUTE_MEMORY_CACHED
177 );
178 if (EFI_ERROR (Status)) {
179 return Status;
180 }
181
182 ZeroMem (RxBuffer, NumBytes);
183
184 Status = Dev->PciIo->Map (
185 Dev->PciIo,
186 EfiPciIoOperationBusMasterCommonBuffer,
187 RxBuffer,
188 &NumBytes,
189 &Dev->RxDeviceBase,
190 &Dev->RxMap
191 );
192 if (EFI_ERROR (Status)) {
193 goto FreeSharedBuffer;
194 }
195
196 Dev->RxRing = RxBuffer;
197 Dev->RxBuf = (UINT8 *)RxBuffer + sizeof(*Dev->RxRing) * E1K_NET_MAX_PENDING;
198 Dev->RdhLastSeen = 0;
199
200 // Set up the RX descriptors.
201 Dev->RxBufDeviceBase = Dev->RxDeviceBase + sizeof(*Dev->RxRing) * E1K_NET_MAX_PENDING;
202 RxBufDeviceAddress = Dev->RxBufDeviceBase;
203 for (PktIdx = 0; PktIdx < E1K_NET_MAX_PENDING; ++PktIdx) {
204 Dev->RxRing[PktIdx].AddrBufferLow = (UINT32)RxBufDeviceAddress;
205 Dev->RxRing[PktIdx].AddrBufferHigh = (UINT32)RShiftU64(RxBufDeviceAddress, 32);
206 Dev->RxRing[PktIdx].BufferLength = 2048;
207
208 RxBufDeviceAddress += Dev->RxRing[PktIdx].BufferLength;
209 }
210
211 // Program the receive engine.
212 MemoryFence ();
213 E1kNetRegWrite32(Dev, E1K_REG_RDBAL, (UINT32)Dev->RxDeviceBase);
214 E1kNetRegWrite32(Dev, E1K_REG_RDBAH, (UINT32)(RShiftU64 (Dev->RxDeviceBase, 32)));
215 E1kNetRegWrite32(Dev, E1K_REG_RDLEN, sizeof(*Dev->RxRing) * E1K_NET_MAX_PENDING);
216 E1kNetRegWrite32(Dev, E1K_REG_RDH, 0);
217 E1kNetRegWrite32(Dev, E1K_REG_RDT, E1K_NET_MAX_PENDING - 1);
218 E1kNetRegClear32(Dev, E1K_REG_RCTL, E1K_REG_RCTL_BSIZE_MASK);
219 E1kNetRegSet32(Dev, E1K_REG_RCTL, E1K_REG_RCTL_EN | E1K_REG_RCTL_MPE);
220
221 return EFI_SUCCESS;
222
223FreeSharedBuffer:
224 Dev->PciIo->FreeBuffer (
225 Dev->PciIo,
226 Dev->RxBufNrPages,
227 RxBuffer
228 );
229 return Status;
230}
231
232/**
233 Resets a network adapter and allocates the transmit and receive buffers
234 required by the network interface; optionally, also requests allocation of
235 additional transmit and receive buffers.
236
237 @param This The protocol instance pointer.
238 @param ExtraRxBufferSize The size, in bytes, of the extra receive buffer
239 space that the driver should allocate for the
240 network interface. Some network interfaces will not
241 be able to use the extra buffer, and the caller
242 will not know if it is actually being used.
243 @param ExtraTxBufferSize The size, in bytes, of the extra transmit buffer
244 space that the driver should allocate for the
245 network interface. Some network interfaces will not
246 be able to use the extra buffer, and the caller
247 will not know if it is actually being used.
248
249 @retval EFI_SUCCESS The network interface was initialized.
250 @retval EFI_NOT_STARTED The network interface has not been started.
251 @retval EFI_OUT_OF_RESOURCES There was not enough memory for the transmit
252 and receive buffers.
253 @retval EFI_INVALID_PARAMETER One or more of the parameters has an
254 unsupported value.
255 @retval EFI_DEVICE_ERROR The command could not be sent to the network
256 interface.
257 @retval EFI_UNSUPPORTED This function is not supported by the network
258 interface.
259
260**/
261
262EFI_STATUS
263EFIAPI
264E1kNetInitialize (
265 IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
266 IN UINTN ExtraRxBufferSize OPTIONAL,
267 IN UINTN ExtraTxBufferSize OPTIONAL
268 )
269{
270 E1K_NET_DEV *Dev;
271 EFI_TPL OldTpl;
272 EFI_STATUS Status;
273
274 DEBUG((DEBUG_INFO, "E1kNetInitialize:\n"));
275
276 if (This == NULL) {
277 return EFI_INVALID_PARAMETER;
278 }
279 if (ExtraRxBufferSize > 0 || ExtraTxBufferSize > 0) {
280 return EFI_UNSUPPORTED;
281 }
282
283 Dev = E1K_NET_FROM_SNP (This);
284 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
285 if (Dev->Snm.State != EfiSimpleNetworkStarted) {
286 Status = EFI_NOT_STARTED;
287 goto InitFailed;
288 }
289
290 // Program the first Receive Address Low/High register.
291 E1kNetRegSet32(Dev, E1K_REG_CTRL, E1K_REG_CTRL_ASDE | E1K_REG_CTRL_SLU);
292 E1kNetRegWrite32(Dev, E1K_REG_RAL, *(UINT32 *)&Dev->Snm.CurrentAddress.Addr[0]);
293 E1kNetRegWrite32(Dev, E1K_REG_RAH, (*(UINT32 *)&Dev->Snm.CurrentAddress.Addr[4]) | E1K_REG_RAH_AV);
294
295 Status = E1kNetInitTx (Dev);
296 if (EFI_ERROR (Status)) {
297 goto AbortDevice;
298 }
299
300 //
301 // start receiving
302 //
303 Status = E1kNetInitRx (Dev);
304 if (EFI_ERROR (Status)) {
305 goto ReleaseTxAux;
306 }
307
308 Dev->Snm.State = EfiSimpleNetworkInitialized;
309 gBS->RestoreTPL (OldTpl);
310 return EFI_SUCCESS;
311
312ReleaseTxAux:
313 E1kNetShutdownTx (Dev);
314
315AbortDevice:
316 E1kNetDevReset(Dev);
317
318InitFailed:
319 gBS->RestoreTPL (OldTpl);
320 return Status;
321}
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use