1 | /** @file
|
---|
2 |
|
---|
3 | Implementation of the SNP.Initialize() function and its private helpers if
|
---|
4 | any.
|
---|
5 |
|
---|
6 | Copyright (c) 2021 - 2024, 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 |
|
---|
40 | STATIC
|
---|
41 | EFI_STATUS
|
---|
42 | EFIAPI
|
---|
43 | E1kNetInitTx (
|
---|
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 |
|
---|
109 | FreeTxRingBuffer:
|
---|
110 | Dev->PciIo->FreeBuffer (
|
---|
111 | Dev->PciIo,
|
---|
112 | EFI_SIZE_TO_PAGES (TxRingSize),
|
---|
113 | TxRingBuffer
|
---|
114 | );
|
---|
115 |
|
---|
116 | UninitTxBufCollection:
|
---|
117 | OrderedCollectionUninit (Dev->TxBufCollection);
|
---|
118 |
|
---|
119 | Exit:
|
---|
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 |
|
---|
140 | STATIC
|
---|
141 | EFI_STATUS
|
---|
142 | EFIAPI
|
---|
143 | E1kNetInitRx (
|
---|
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 |
|
---|
223 | FreeSharedBuffer:
|
---|
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 |
|
---|
262 | EFI_STATUS
|
---|
263 | EFIAPI
|
---|
264 | E1kNetInitialize (
|
---|
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 |
|
---|
312 | ReleaseTxAux:
|
---|
313 | E1kNetShutdownTx (Dev);
|
---|
314 |
|
---|
315 | AbortDevice:
|
---|
316 | E1kNetDevReset(Dev);
|
---|
317 |
|
---|
318 | InitFailed:
|
---|
319 | gBS->RestoreTPL (OldTpl);
|
---|
320 | return Status;
|
---|
321 | }
|
---|