]> git.proxmox.com Git - mirror_edk2.git/blame - EmbeddedPkg/Drivers/Lan9118Dxe/Lan9118Dxe.c
ArmPkg: Fix typos in comments
[mirror_edk2.git] / EmbeddedPkg / Drivers / Lan9118Dxe / Lan9118Dxe.c
CommitLineData
46f2c53b
OM
1/** @file\r
2*\r
3* Copyright (c) 2012-2014, ARM Limited. All rights reserved.\r
4*\r
5* This program and the accompanying materials\r
6* are licensed and made available under the terms and conditions of the BSD License\r
7* which accompanies this distribution. The full text of the license may be found at\r
8* http://opensource.org/licenses/bsd-license.php\r
9*\r
10* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12*\r
13**/\r
14\r
15#include "Lan9118Dxe.h"\r
16\r
46f2c53b
OM
17typedef struct {\r
18 MAC_ADDR_DEVICE_PATH Lan9118;\r
19 EFI_DEVICE_PATH_PROTOCOL End;\r
20} LAN9118_DEVICE_PATH;\r
21\r
22LAN9118_DEVICE_PATH Lan9118PathTemplate = {\r
23 {\r
24 {\r
25 MESSAGING_DEVICE_PATH, MSG_MAC_ADDR_DP,\r
26 { (UINT8) (sizeof(MAC_ADDR_DEVICE_PATH)), (UINT8) ((sizeof(MAC_ADDR_DEVICE_PATH)) >> 8) }\r
27 },\r
b0fdce95 28 { { 0 } },\r
46f2c53b
OM
29 0\r
30 },\r
31 {\r
32 END_DEVICE_PATH_TYPE,\r
33 END_ENTIRE_DEVICE_PATH_SUBTYPE,\r
b0fdce95 34 { sizeof(EFI_DEVICE_PATH_PROTOCOL), 0 }\r
46f2c53b
OM
35 }\r
36};\r
37\r
38/*\r
39** Entry point for the LAN9118 driver\r
40**\r
41*/\r
42EFI_STATUS\r
43Lan9118DxeEntry (\r
44 IN EFI_HANDLE Handle,\r
45 IN EFI_SYSTEM_TABLE *SystemTable\r
46 )\r
47{\r
48 EFI_STATUS Status;\r
49 LAN9118_DRIVER *LanDriver;\r
50 EFI_SIMPLE_NETWORK_PROTOCOL *Snp;\r
51 EFI_SIMPLE_NETWORK_MODE *SnpMode;\r
52 LAN9118_DEVICE_PATH *Lan9118Path;\r
53 EFI_HANDLE ControllerHandle;\r
54\r
55 // The PcdLan9118DxeBaseAddress PCD must be defined\r
56 ASSERT (PcdGet32 (PcdLan9118DxeBaseAddress) != 0);\r
57\r
58 // Allocate Resources\r
59 LanDriver = AllocateZeroPool (sizeof (LAN9118_DRIVER));\r
60 if (LanDriver == NULL) {\r
61 return EFI_OUT_OF_RESOURCES;\r
62 }\r
63 Lan9118Path = (LAN9118_DEVICE_PATH*)AllocateCopyPool (sizeof (LAN9118_DEVICE_PATH), &Lan9118PathTemplate);\r
64 if (Lan9118Path == NULL) {\r
65 return EFI_OUT_OF_RESOURCES;\r
66 }\r
67\r
68 // Initialize pointers\r
69 Snp = &(LanDriver->Snp);\r
70 SnpMode = &(LanDriver->SnpMode);\r
71 Snp->Mode = SnpMode;\r
72\r
73 // Set the signature of the LAN Driver structure\r
74 LanDriver->Signature = LAN9118_SIGNATURE;\r
75\r
76 // Assign fields and func pointers\r
77 Snp->Revision = EFI_SIMPLE_NETWORK_PROTOCOL_REVISION;\r
78 Snp->WaitForPacket = NULL;\r
79 Snp->Initialize = SnpInitialize;\r
80 Snp->Start = SnpStart;\r
81 Snp->Stop = SnpStop;\r
82 Snp->Reset = SnpReset;\r
83 Snp->Shutdown = SnpShutdown;\r
84 Snp->ReceiveFilters = SnpReceiveFilters;\r
85 Snp->StationAddress = SnpStationAddress;\r
86 Snp->Statistics = SnpStatistics;\r
87 Snp->MCastIpToMac = SnpMcastIptoMac;\r
88 Snp->NvData = SnpNvData;\r
89 Snp->GetStatus = SnpGetStatus;\r
90 Snp->Transmit = SnpTransmit;\r
91 Snp->Receive = SnpReceive;\r
92\r
93 // Start completing simple network mode structure\r
94 SnpMode->State = EfiSimpleNetworkStopped;\r
95 SnpMode->HwAddressSize = NET_ETHER_ADDR_LEN; // HW address is 6 bytes\r
96 SnpMode->MediaHeaderSize = sizeof(ETHER_HEAD); // Not sure of this\r
97 SnpMode->MaxPacketSize = EFI_PAGE_SIZE; // Preamble + SOF + Ether Frame (with VLAN tag +4bytes)\r
98 SnpMode->NvRamSize = 0; // No NVRAM with this device\r
99 SnpMode->NvRamAccessSize = 0; // No NVRAM with this device\r
100\r
11bbc257
RC
101 //\r
102 // Claim that all receive filter settings are supported, though the MULTICAST mode\r
103 // is not completely supported. The LAN9118 Ethernet controller is only able to\r
104 // do a "hash filtering" and not a perfect filtering on multicast addresses. The\r
105 // controller does not filter the multicast addresses directly but a hash value\r
106 // of them. The hash value of a multicast address is derived from its CRC and\r
107 // ranges from 0 to 63 included.\r
108 // We claim that the perfect MULTICAST filtering mode is supported because\r
109 // we do not want the user to switch directly to the PROMISCOUS_MULTICAST mode\r
110 // and thus not being able to take advantage of the hash filtering.\r
111 //\r
112 SnpMode->ReceiveFilterMask = EFI_SIMPLE_NETWORK_RECEIVE_UNICAST |\r
113 EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST |\r
114 EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST |\r
115 EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS |\r
116 EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST;\r
117\r
118 // We do not intend to receive anything for the time being.\r
119 SnpMode->ReceiveFilterSetting = 0;\r
46f2c53b
OM
120\r
121 // LAN9118 has 64bit hash table, can filter 64 MCast MAC Addresses\r
122 SnpMode->MaxMCastFilterCount = MAX_MCAST_FILTER_CNT;\r
123 SnpMode->MCastFilterCount = 0;\r
124 ZeroMem (&SnpMode->MCastFilter, MAX_MCAST_FILTER_CNT * sizeof(EFI_MAC_ADDRESS));\r
125\r
126 // Set the interface type (1: Ethernet or 6: IEEE 802 Networks)\r
127 SnpMode->IfType = NET_IFTYPE_ETHERNET;\r
128\r
129 // Mac address is changeable as it is loaded from erasable memory\r
130 SnpMode->MacAddressChangeable = TRUE;\r
131\r
132 // Can only transmit one packet at a time\r
133 SnpMode->MultipleTxSupported = FALSE;\r
134\r
135 // MediaPresent checks for cable connection and partner link\r
136 SnpMode->MediaPresentSupported = TRUE;\r
137 SnpMode->MediaPresent = FALSE;\r
138\r
139 // Set broadcast address\r
140 SetMem (&SnpMode->BroadcastAddress, sizeof (EFI_MAC_ADDRESS), 0xFF);\r
141\r
142 // Power up the device so we can find the MAC address\r
143 Status = Lan9118Initialize (Snp);\r
144 if (EFI_ERROR (Status)) {\r
c64aa7c4 145 DEBUG ((EFI_D_ERROR, "LAN9118: Error initialising hardware\n"));\r
46f2c53b
OM
146 return EFI_DEVICE_ERROR;\r
147 }\r
148\r
149 // Assign fields for device path\r
150 CopyMem (&Lan9118Path->Lan9118.MacAddress, &Snp->Mode->CurrentAddress, NET_ETHER_ADDR_LEN);\r
151 Lan9118Path->Lan9118.IfType = Snp->Mode->IfType;\r
152\r
153 // Initialise the protocol\r
154 ControllerHandle = NULL;\r
155 Status = gBS->InstallMultipleProtocolInterfaces (\r
156 &ControllerHandle,\r
157 &gEfiSimpleNetworkProtocolGuid, Snp,\r
158 &gEfiDevicePathProtocolGuid, Lan9118Path,\r
159 NULL\r
160 );\r
161 // Say what the status of loading the protocol structure is\r
162 if (EFI_ERROR(Status)) {\r
163 FreePool (LanDriver);\r
164 } else {\r
165 LanDriver->ControllerHandle = ControllerHandle;\r
166 }\r
167\r
168 return Status;\r
169}\r
170\r
171/*\r
172 * UEFI Start() function\r
173 *\r
174 * Parameters:\r
175 *\r
176 * @param Snp: A pointer to the EFI_SIMPLE_NETWORK_PROTOCOL instance.\r
177 *\r
178 * Description:\r
179 *\r
180 * This function starts a network interface. If the network interface successfully starts, then\r
181 * EFI_SUCCESS will be returned.\r
182 */\r
183EFI_STATUS\r
184EFIAPI\r
185SnpStart (\r
0150e14d 186 IN EFI_SIMPLE_NETWORK_PROTOCOL *Snp\r
46f2c53b
OM
187 )\r
188{\r
189 // Check Snp instance\r
190 if (Snp == NULL) {\r
191 return EFI_INVALID_PARAMETER;\r
192 }\r
193\r
194 // Check state\r
0150e14d
RC
195 if ((Snp->Mode->State == EfiSimpleNetworkStarted) ||\r
196 (Snp->Mode->State == EfiSimpleNetworkInitialized) ) {\r
46f2c53b 197 return EFI_ALREADY_STARTED;\r
46f2c53b
OM
198 }\r
199\r
200 // Change state\r
201 Snp->Mode->State = EfiSimpleNetworkStarted;\r
202 return EFI_SUCCESS;\r
203}\r
204\r
205/*\r
206 * UEFI Stop() function\r
207 *\r
208 */\r
209EFI_STATUS\r
210EFIAPI\r
211SnpStop (\r
212 IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp\r
213 )\r
214{\r
215 // Check Snp Instance\r
216 if (Snp == NULL) {\r
217 return EFI_INVALID_PARAMETER;\r
218 }\r
219\r
220 // Check state of the driver\r
0150e14d 221 if (Snp->Mode->State == EfiSimpleNetworkStopped) {\r
46f2c53b
OM
222 return EFI_NOT_STARTED;\r
223 }\r
224\r
225 // Stop the Tx and Rx\r
226 StopTx (STOP_TX_CFG | STOP_TX_MAC, Snp);\r
227 StopRx (0, Snp);\r
228\r
229 // Change the state\r
230 switch (Snp->Mode->State) {\r
231 case EfiSimpleNetworkStarted:\r
232 case EfiSimpleNetworkInitialized:\r
233 Snp->Mode->State = EfiSimpleNetworkStopped;\r
234 break;\r
235 default:\r
236 return EFI_DEVICE_ERROR;\r
237 }\r
238\r
239 // Put the device into a power saving mode ?\r
240 return EFI_SUCCESS;\r
241}\r
242\r
243\r
244// Allocated receive and transmit buffers\r
245STATIC UINT32 gTxBuffer = 0;\r
246\r
247/*\r
248 * UEFI Initialize() function\r
249 *\r
250 */\r
251EFI_STATUS\r
252EFIAPI\r
253SnpInitialize (\r
254 IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp,\r
255 IN UINTN RxBufferSize OPTIONAL,\r
256 IN UINTN TxBufferSize OPTIONAL\r
257 )\r
258{\r
259 EFI_STATUS Status;\r
260 UINT32 PmConf;\r
261 INT32 AllocResult;\r
262 UINT32 RxStatusSize;\r
263 UINT32 TxStatusSize;\r
264\r
265 // Initialize variables\r
266 // Global variables to hold tx and rx FIFO allocation\r
267 gTxBuffer = 0;\r
268\r
269 // Check Snp Instance\r
270 if (Snp == NULL) {\r
271 return EFI_INVALID_PARAMETER;\r
272 }\r
273\r
274 // First check that driver has not already been initialized\r
275 if (Snp->Mode->State == EfiSimpleNetworkInitialized) {\r
276 DEBUG ((EFI_D_WARN, "LAN9118 Driver already initialized\n"));\r
277 return EFI_SUCCESS;\r
278 } else\r
279 if (Snp->Mode->State == EfiSimpleNetworkStopped) {\r
280 DEBUG ((EFI_D_WARN, "LAN9118 Driver not started\n"));\r
281 return EFI_NOT_STARTED;\r
282 }\r
283\r
284 // Initiate a PHY reset\r
6382e5df 285 Status = PhySoftReset (PHY_RESET_PMT, Snp);\r
42589b9a 286 if (EFI_ERROR (Status)) {\r
46f2c53b
OM
287 Snp->Mode->State = EfiSimpleNetworkStopped;\r
288 DEBUG ((EFI_D_WARN, "Warning: Link not ready after TimeOut. Check ethernet cable\n"));\r
289 return EFI_NOT_STARTED;\r
290 }\r
291\r
292 // Initiate a software reset\r
293 Status = SoftReset (0, Snp);\r
294 if (EFI_ERROR(Status)) {\r
295 DEBUG ((EFI_D_WARN, "Soft Reset Failed: Hardware Error\n"));\r
296 return EFI_DEVICE_ERROR;\r
297 }\r
298\r
299 // Read the PM register\r
e68449c9 300 PmConf = Lan9118MmioRead32 (LAN9118_PMT_CTRL);\r
46f2c53b
OM
301\r
302 // MPTCTRL_WOL_EN: Allow Wake-On-Lan to detect wake up frames or magic packets\r
303 // MPTCTRL_ED_EN: Allow energy detection to allow lowest power consumption mode\r
304 // MPTCTRL_PME_EN: Allow Power Management Events\r
305 PmConf = 0;\r
306 PmConf |= (MPTCTRL_WOL_EN | MPTCTRL_ED_EN | MPTCTRL_PME_EN);\r
307\r
308 // Write the current configuration to the register\r
e68449c9 309 Lan9118MmioWrite32 (LAN9118_PMT_CTRL, PmConf);\r
46f2c53b
OM
310\r
311 // Configure GPIO and HW\r
312 Status = ConfigureHardware (HW_CONF_USE_LEDS, Snp);\r
313 if (EFI_ERROR(Status)) {\r
314 return Status;\r
315 }\r
316\r
317 // Assign the transmitter buffer size (default values)\r
318 TxStatusSize = LAN9118_TX_STATUS_SIZE;\r
319 RxStatusSize = LAN9118_RX_STATUS_SIZE;\r
320\r
321 // Check that a buff size was specified\r
322 if (TxBufferSize > 0) {\r
323 if (RxBufferSize == 0) {\r
324 RxBufferSize = LAN9118_RX_DATA_SIZE;\r
325 }\r
326\r
327 AllocResult = ChangeFifoAllocation (\r
328 ALLOC_USE_FIFOS,\r
329 &TxBufferSize,\r
330 &RxBufferSize,\r
331 &TxStatusSize,\r
332 &RxStatusSize,\r
333 Snp\r
334 );\r
335\r
336 if (AllocResult < 0) {\r
337 return EFI_OUT_OF_RESOURCES;\r
338 }\r
339 }\r
340\r
341 // Do auto-negotiation if supported\r
342 Status = AutoNegotiate (AUTO_NEGOTIATE_ADVERTISE_ALL, Snp);\r
343 if (EFI_ERROR(Status)) {\r
c64aa7c4 344 DEBUG ((EFI_D_WARN, "LAN9118: Auto Negotiation failed.\n"));\r
46f2c53b
OM
345 }\r
346\r
347 // Configure flow control depending on speed capabilities\r
348 Status = ConfigureFlow (0, 0, 0, 0, Snp);\r
349 if (EFI_ERROR(Status)) {\r
350 return Status;\r
351 }\r
352\r
11bbc257 353 // Enable the transmitter\r
46f2c53b
OM
354 Status = StartTx (START_TX_MAC | START_TX_CFG, Snp);\r
355 if (EFI_ERROR(Status)) {\r
356 return Status;\r
357 }\r
358\r
359 // Now acknowledge all interrupts\r
e68449c9 360 Lan9118MmioWrite32 (LAN9118_INT_STS, ~0);\r
46f2c53b
OM
361\r
362 // Declare the driver as initialized\r
363 Snp->Mode->State = EfiSimpleNetworkInitialized;\r
364\r
365 return Status;\r
366}\r
367\r
368/*\r
369 * UEFI Reset () function\r
370 *\r
371 */\r
372EFI_STATUS\r
373EFIAPI\r
374SnpReset (\r
375 IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp,\r
376 IN BOOLEAN Verification\r
377 )\r
378{\r
42589b9a
OM
379 UINT32 PmConf;\r
380 UINT32 HwConf;\r
381 UINT32 ResetFlags;\r
382 EFI_STATUS Status;\r
46f2c53b
OM
383\r
384 PmConf = 0;\r
385 HwConf = 0;\r
386 ResetFlags = 0;\r
387\r
388 // Check Snp Instance\r
389 if (Snp == NULL) {\r
390 return EFI_INVALID_PARAMETER;\r
391 }\r
392\r
393 // First check that driver has not already been initialized\r
394 if (Snp->Mode->State == EfiSimpleNetworkStarted) {\r
395 DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver not yet initialized\n"));\r
396 return EFI_DEVICE_ERROR;\r
397 } else if (Snp->Mode->State == EfiSimpleNetworkStopped) {\r
398 DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver not started\n"));\r
399 return EFI_NOT_STARTED;\r
400 }\r
401\r
402 // Initiate a PHY reset\r
6382e5df 403 Status = PhySoftReset (PHY_RESET_PMT, Snp);\r
42589b9a 404 if (EFI_ERROR (Status)) {\r
46f2c53b
OM
405 Snp->Mode->State = EfiSimpleNetworkStopped;\r
406 return EFI_NOT_STARTED;\r
407 }\r
408\r
409 // Initiate a software reset\r
410 ResetFlags |= SOFT_RESET_CHECK_MAC_ADDR_LOAD | SOFT_RESET_CLEAR_INT;\r
411\r
412 if (Verification) {\r
413 ResetFlags |= SOFT_RESET_SELF_TEST;\r
414 }\r
415\r
42589b9a
OM
416 Status = SoftReset (ResetFlags, Snp);\r
417 if (EFI_ERROR (Status)) {\r
46f2c53b
OM
418 DEBUG ((EFI_D_WARN, "Warning: Soft Reset Failed: Hardware Error\n"));\r
419 return EFI_DEVICE_ERROR;\r
420 }\r
421\r
422 // Read the PM register\r
e68449c9 423 PmConf = Lan9118MmioRead32 (LAN9118_PMT_CTRL);\r
46f2c53b
OM
424\r
425 // MPTCTRL_WOL_EN: Allow Wake-On-Lan to detect wake up frames or magic packets\r
426 // MPTCTRL_ED_EN: Allow energy detection to allow lowest power consumption mode\r
427 // MPTCTRL_PME_EN: Allow Power Management Events\r
428 PmConf |= (MPTCTRL_WOL_EN | MPTCTRL_ED_EN | MPTCTRL_PME_EN);\r
429\r
430 // Write the current configuration to the register\r
e68449c9 431 Lan9118MmioWrite32 (LAN9118_PMT_CTRL, PmConf);\r
46f2c53b 432\r
ac8f1e10
RC
433 // Reactivate the LEDs\r
434 Status = ConfigureHardware (HW_CONF_USE_LEDS, Snp);\r
435 if (EFI_ERROR (Status)) {\r
436 return Status;\r
437 }\r
438\r
46f2c53b
OM
439 // Check that a buffer size was specified in SnpInitialize\r
440 if (gTxBuffer != 0) {\r
e68449c9 441 HwConf = Lan9118MmioRead32 (LAN9118_HW_CFG); // Read the HW register\r
46f2c53b
OM
442 HwConf &= ~HW_CFG_TX_FIFO_SIZE_MASK; // Clear buffer bits first\r
443 HwConf |= HW_CFG_TX_FIFO_SIZE(gTxBuffer); // assign size chosen in SnpInitialize\r
444\r
e68449c9 445 Lan9118MmioWrite32 (LAN9118_HW_CFG, HwConf); // Write the conf\r
46f2c53b
OM
446 }\r
447\r
448 // Enable the receiver and transmitter and clear their contents\r
449 StartRx (START_RX_CLEAR, Snp);\r
450 StartTx (START_TX_MAC | START_TX_CFG | START_TX_CLEAR, Snp);\r
451\r
452 // Now acknowledge all interrupts\r
e68449c9 453 Lan9118MmioWrite32 (LAN9118_INT_STS, ~0);\r
46f2c53b
OM
454\r
455 return EFI_SUCCESS;\r
456}\r
457\r
458/*\r
459 * UEFI Shutdown () function\r
460 *\r
461 */\r
462EFI_STATUS\r
463EFIAPI\r
464SnpShutdown (\r
465 IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp\r
466 )\r
467{\r
42589b9a
OM
468 EFI_STATUS Status;\r
469\r
46f2c53b
OM
470 // Check Snp Instance\r
471 if (Snp == NULL) {\r
472 return EFI_INVALID_PARAMETER;\r
473 }\r
474\r
475 // First check that driver has not already been initialized\r
476 if (Snp->Mode->State == EfiSimpleNetworkStarted) {\r
477 DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver not yet initialized\n"));\r
478 return EFI_DEVICE_ERROR;\r
479 } else if (Snp->Mode->State == EfiSimpleNetworkStopped) {\r
0150e14d 480 DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver not started\n"));\r
46f2c53b
OM
481 return EFI_NOT_STARTED;\r
482 }\r
483\r
484 // Initiate a PHY reset\r
42589b9a
OM
485 Status = PhySoftReset (PHY_RESET_PMT, Snp);\r
486 if (EFI_ERROR (Status)) {\r
487 return Status;\r
488 }\r
46f2c53b
OM
489\r
490 // Initiate a software reset\r
42589b9a
OM
491 Status = SoftReset (0, Snp);\r
492 if (EFI_ERROR (Status)) {\r
46f2c53b 493 DEBUG ((EFI_D_WARN, "Warning: Soft Reset Failed: Hardware Error\n"));\r
42589b9a 494 return Status;\r
46f2c53b
OM
495 }\r
496\r
0f0a6fe9
RC
497 // Back to the started and thus not initialized state\r
498 Snp->Mode->State = EfiSimpleNetworkStarted;\r
499\r
46f2c53b
OM
500 return EFI_SUCCESS;\r
501}\r
502\r
0150e14d
RC
503/**\r
504 Enable and/or disable the receive filters of the LAN9118\r
505\r
506 Please refer to the UEFI specification for the precedence rules among the\r
507 Enable, Disable and ResetMCastFilter parameters.\r
508\r
509 @param[in] Snp A pointer to the EFI_SIMPLE_NETWORK_PROTOCOL\r
510 instance.\r
511 @param[in] Enable A bit mask of receive filters to enable.\r
512 @param[in] Disable A bit mask of receive filters to disable.\r
513 @param[in] ResetMCastFilter Set to TRUE to reset the contents of the multicast\r
514 receive filters on the network interface to\r
515 their default values.\r
516 @param[in] MCastFilterCnt Number of multicast HW MAC addresses in the new\r
517 MCastFilter list. This value must be less than or\r
518 equal to the MCastFilterCnt field of\r
519 EFI_SIMPLE_NETWORK_MODE. This field is optional if\r
520 ResetMCastFilter is TRUE.\r
521 @param[in] MCastFilter A pointer to a list of new multicast receive\r
522 filter HW MAC addresses. This list will replace\r
523 any existing multicast HW MAC address list. This\r
524 field is optional if ResetMCastFilter is TRUE.\r
525\r
526 @retval EFI_SUCCESS The receive filters of the LAN9118 were updated.\r
527 @retval EFI_NOT_STARTED The LAN9118 has not been started.\r
528 @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE :\r
529 . This is NULL\r
530 . Multicast is being enabled (the\r
531 EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST bit is set in\r
532 Enable, it is not set in Disable, and ResetMCastFilter\r
533 is FALSE) and MCastFilterCount is zero.\r
534 . Multicast is being enabled and MCastFilterCount is\r
535 greater than Snp->Mode->MaxMCastFilterCount.\r
536 . Multicast is being enabled and MCastFilter is NULL\r
537 . Multicast is being enabled and one or more of the\r
538 addresses in the MCastFilter list are not valid\r
539 multicast MAC addresses.\r
540 @retval EFI_DEVICE_ERROR The LAN9118 has been started but not initialized.\r
46f2c53b 541\r
0150e14d 542**/\r
46f2c53b
OM
543EFI_STATUS\r
544EFIAPI\r
545SnpReceiveFilters (\r
0150e14d
RC
546 IN EFI_SIMPLE_NETWORK_PROTOCOL *Snp,\r
547 IN UINT32 Enable,\r
548 IN UINT32 Disable,\r
549 IN BOOLEAN ResetMCastFilter,\r
550 IN UINTN MCastFilterCnt OPTIONAL,\r
551 IN EFI_MAC_ADDRESS *MCastFilter OPTIONAL\r
46f2c53b
OM
552 )\r
553{\r
0150e14d
RC
554 EFI_SIMPLE_NETWORK_MODE *Mode;\r
555 UINT32 MultHashTableHigh;\r
556 UINT32 MultHashTableLow;\r
557 UINT32 Count;\r
558 UINT32 Crc;\r
559 UINT8 HashValue;\r
560 UINT32 MacCSRValue;\r
11bbc257 561 UINT32 ReceiveFilterSetting;\r
0150e14d 562 EFI_MAC_ADDRESS *Mac;\r
11bbc257 563 EFI_MAC_ADDRESS ZeroMac;\r
46f2c53b 564\r
0150e14d
RC
565 // Check Snp Instance\r
566 if (Snp == NULL) {\r
567 return EFI_INVALID_PARAMETER;\r
568 }\r
569 Mode = Snp->Mode;\r
46f2c53b
OM
570\r
571 // Check that driver was started and initialised\r
0150e14d 572 if (Mode->State == EfiSimpleNetworkStarted) {\r
46f2c53b
OM
573 DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver not initialized\n"));\r
574 return EFI_DEVICE_ERROR;\r
0150e14d 575 } else if (Mode->State == EfiSimpleNetworkStopped) {\r
46f2c53b
OM
576 DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver in stopped state\n"));\r
577 return EFI_NOT_STARTED;\r
578 }\r
579\r
0150e14d
RC
580 if ((Enable & (~Mode->ReceiveFilterMask)) ||\r
581 (Disable & (~Mode->ReceiveFilterMask)) ) {\r
582 return EFI_INVALID_PARAMETER;\r
46f2c53b
OM
583 }\r
584\r
0150e14d
RC
585 //\r
586 // Check the validity of the multicast setting and compute the\r
587 // hash values of the multicast mac addresses to listen to.\r
588 //\r
46f2c53b 589\r
0150e14d
RC
590 MultHashTableHigh = 0;\r
591 MultHashTableLow = 0;\r
592 if ((!ResetMCastFilter) &&\r
593 ((Disable & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST) == 0) &&\r
594 ((Enable & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST) != 0) ) {\r
595 if ((MCastFilterCnt == 0) ||\r
596 (MCastFilterCnt > Mode->MaxMCastFilterCount) ||\r
597 (MCastFilter == NULL) ) {\r
598 return EFI_INVALID_PARAMETER;\r
599 }\r
600 //\r
601 // Check the validity of all multicast addresses before to change\r
602 // anything.\r
603 //\r
604 for (Count = 0; Count < MCastFilterCnt; Count++) {\r
605 if ((MCastFilter[Count].Addr[0] & 1) == 0) {\r
606 return EFI_INVALID_PARAMETER;\r
607 }\r
608 }\r
46f2c53b 609\r
0150e14d 610 //\r
46f2c53b 611 // Go through each filter address and set appropriate bits on hash table\r
0150e14d
RC
612 //\r
613 for (Count = 0; Count < MCastFilterCnt; Count++) {\r
614 Mac = &(MCastFilter[Count]);\r
615 CopyMem (&Mode->MCastFilter[Count], Mac, sizeof(EFI_MAC_ADDRESS));\r
46f2c53b 616\r
0150e14d 617 Crc = GenEtherCrc32 (Mac, NET_ETHER_ADDR_LEN);\r
46f2c53b
OM
618 //gBS->CalculateCrc32 ((VOID*)&Mfilter[Count],6,&Crc); <-- doesn't work as desired\r
619\r
0150e14d
RC
620 //\r
621 // The most significant 6 bits of the MAC address CRC constitute the hash\r
622 // value of the MAC address.\r
623 //\r
624 HashValue = (Crc >> 26) & 0x3F;\r
46f2c53b
OM
625\r
626 // Select hashlow register if MSB is not set\r
0150e14d
RC
627 if ((HashValue & 0x20) == 0) {\r
628 MultHashTableLow |= (1 << HashValue);\r
46f2c53b 629 } else {\r
0150e14d 630 MultHashTableHigh |= (1 << (HashValue & 0x1F));\r
46f2c53b
OM
631 }\r
632 }\r
0150e14d
RC
633 Mode->MCastFilterCount = MCastFilterCnt;\r
634 } else if (ResetMCastFilter) {\r
635 Mode->MCastFilterCount = 0;\r
636 } else {\r
637 MultHashTableLow = IndirectMACRead32 (INDIRECT_MAC_INDEX_HASHL);\r
638 MultHashTableHigh = IndirectMACRead32 (INDIRECT_MAC_INDEX_HASHH);\r
46f2c53b
OM
639 }\r
640\r
11bbc257
RC
641 //\r
642 // Before to change anything, stop and reset the reception of\r
643 // packets.\r
644 //\r
645 StopRx (STOP_RX_CLEAR, Snp);\r
646\r
0150e14d
RC
647 //\r
648 // Write the mask of the selected hash values for the multicast filtering.\r
649 // The two masks are set to zero if the multicast filtering is not enabled.\r
650 //\r
651 IndirectMACWrite32 (INDIRECT_MAC_INDEX_HASHL, MultHashTableLow);\r
652 IndirectMACWrite32 (INDIRECT_MAC_INDEX_HASHH, MultHashTableHigh);\r
653\r
11bbc257
RC
654 ReceiveFilterSetting = (Mode->ReceiveFilterSetting | Enable) & (~Disable);\r
655\r
656 //\r
46f2c53b 657 // Read MAC controller\r
11bbc257
RC
658 //\r
659 MacCSRValue = IndirectMACRead32 (INDIRECT_MAC_INDEX_CR);\r
660 MacCSRValue &= ~(MACCR_HPFILT | MACCR_BCAST | MACCR_PRMS | MACCR_MCPAS);\r
46f2c53b 661\r
11bbc257
RC
662 if (ReceiveFilterSetting & EFI_SIMPLE_NETWORK_RECEIVE_UNICAST) {\r
663 Lan9118SetMacAddress (&Mode->CurrentAddress, Snp);\r
46f2c53b 664 DEBUG ((DEBUG_NET, "Allowing Unicast Frame Reception\n"));\r
11bbc257
RC
665 } else {\r
666 //\r
667 // The Unicast packets do not have to be listen to, set the MAC\r
668 // address of the LAN9118 to be the "not configured" all zeroes\r
669 // ethernet MAC address.\r
670 //\r
671 ZeroMem (&ZeroMac, NET_ETHER_ADDR_LEN);\r
672 Lan9118SetMacAddress (&ZeroMac, Snp);\r
46f2c53b
OM
673 }\r
674\r
11bbc257 675 if (ReceiveFilterSetting & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST) {\r
46f2c53b
OM
676 MacCSRValue |= MACCR_HPFILT;\r
677 DEBUG ((DEBUG_NET, "Allowing Multicast Frame Reception\n"));\r
678 }\r
679\r
11bbc257
RC
680 if (ReceiveFilterSetting & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST) {\r
681 MacCSRValue |= MACCR_MCPAS;\r
682 DEBUG ((DEBUG_NET, "Enabling Promiscuous Multicast Mode\n"));\r
46f2c53b
OM
683 }\r
684\r
11bbc257 685 if ((ReceiveFilterSetting & EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST) == 0) {\r
46f2c53b 686 MacCSRValue |= MACCR_BCAST;\r
11bbc257
RC
687 } else {\r
688 DEBUG ((DEBUG_NET, "Allowing Broadcast Frame Reception\n"));\r
46f2c53b
OM
689 }\r
690\r
11bbc257 691 if (ReceiveFilterSetting & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS) {\r
46f2c53b
OM
692 MacCSRValue |= MACCR_PRMS;\r
693 DEBUG ((DEBUG_NET, "Enabling Promiscuous Mode\n"));\r
694 }\r
695\r
11bbc257 696 //\r
46f2c53b 697 // Write the options to the MAC_CSR\r
11bbc257 698 //\r
46f2c53b 699 IndirectMACWrite32 (INDIRECT_MAC_INDEX_CR, MacCSRValue);\r
46f2c53b 700\r
11bbc257
RC
701 //\r
702 // If we have to retrieve something, start packet reception.\r
703 //\r
704 Mode->ReceiveFilterSetting = ReceiveFilterSetting;\r
705 if (ReceiveFilterSetting != 0) {\r
706 StartRx (0, Snp);\r
707 }\r
708\r
46f2c53b
OM
709 return EFI_SUCCESS;\r
710}\r
711\r
0150e14d
RC
712/**\r
713 Modify of reset the current station address\r
714\r
715 @param[in] Snp A pointer to the EFI_SIMPLE_NETWORK_PROTOCOL\r
716 instance.\r
717 @param[in] Reset Flag used to reset the station address to the\r
718 LAN9118's permanent address.\r
719 @param[in] New New station address to be used for the network interface.\r
720\r
721 @retval EFI_SUCCESS The LAN9118's station address was updated.\r
722 @retval EFI_NOT_STARTED The LAN9118 has not been started.\r
723 @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE :\r
724 . The "New" station address is invalid.\r
725 . "Reset" is FALSE and "New" is NULL.\r
726 @retval EFI_DEVICE_ERROR The LAN9118 has been started but not initialized.\r
727\r
728**/\r
46f2c53b
OM
729EFI_STATUS\r
730EFIAPI\r
731SnpStationAddress (\r
0150e14d
RC
732 IN EFI_SIMPLE_NETWORK_PROTOCOL *Snp,\r
733 IN BOOLEAN Reset,\r
734 IN EFI_MAC_ADDRESS *New\r
46f2c53b
OM
735)\r
736{\r
46f2c53b 737 UINT32 Count;\r
0150e14d 738 UINT8 PermAddr[NET_ETHER_ADDR_LEN];\r
46f2c53b 739\r
0150e14d 740 DEBUG ((DEBUG_NET, "SnpStationAddress()\n"));\r
46f2c53b
OM
741\r
742 // Check Snp instance\r
743 if (Snp == NULL) {\r
744 return EFI_INVALID_PARAMETER;\r
745 }\r
746\r
747 // Check that driver was started and initialised\r
748 if (Snp->Mode->State == EfiSimpleNetworkStarted) {\r
749 DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver not initialized\n"));\r
750 return EFI_DEVICE_ERROR;\r
751 } else if (Snp->Mode->State == EfiSimpleNetworkStopped) {\r
752 DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver in stopped state\n"));\r
753 return EFI_NOT_STARTED;\r
754 }\r
755\r
756 // Get the Permanent MAC address if need reset\r
757 if (Reset) {\r
758 // Try using EEPROM first. Read the first byte of data from EEPROM at the address 0x0\r
759 if ((IndirectEEPROMRead32 (0) & 0xFF) == EEPROM_EXTERNAL_SERIAL_EEPROM) {\r
0150e14d
RC
760 for (Count = 0; Count < NET_ETHER_ADDR_LEN; Count++) {\r
761 PermAddr[Count] = IndirectEEPROMRead32 (Count + 1);\r
46f2c53b 762 }\r
0150e14d 763 New = (EFI_MAC_ADDRESS *) PermAddr;\r
46f2c53b
OM
764 Lan9118SetMacAddress ((EFI_MAC_ADDRESS *) PermAddr, Snp);\r
765 } else {\r
c64aa7c4 766 DEBUG ((EFI_D_ERROR, "LAN9118: Warning: No valid MAC address in EEPROM, using fallback\n"));\r
0150e14d 767 New = (EFI_MAC_ADDRESS*) (FixedPcdGet64 (PcdLan9118DefaultMacAddress));\r
46f2c53b
OM
768 }\r
769 } else {\r
770 // Otherwise use the specified new MAC address\r
0150e14d
RC
771 if (New == NULL) {\r
772 return EFI_INVALID_PARAMETER;\r
773 }\r
774 //\r
775 // If it is a multicast address, it is not valid.\r
776 //\r
777 if (New->Addr[0] & 0x01) {\r
46f2c53b
OM
778 return EFI_INVALID_PARAMETER;\r
779 }\r
46f2c53b
OM
780 }\r
781\r
11bbc257
RC
782 CopyMem (&Snp->Mode->CurrentAddress, New, NET_ETHER_ADDR_LEN);\r
783\r
784 //\r
785 // If packet reception is currently activated, stop and reset it,\r
786 // set the new ethernet address and restart the packet reception.\r
787 // Otherwise, nothing to do, the MAC address will be updated in\r
788 // SnpReceiveFilters() when the UNICAST packet reception will be\r
789 // activated.\r
790 //\r
791 if (Snp->Mode->ReceiveFilterSetting != 0) {\r
792 StopRx (STOP_RX_CLEAR, Snp);\r
793 Lan9118SetMacAddress (New, Snp);\r
794 StartRx (0, Snp);\r
795 }\r
0150e14d 796\r
46f2c53b
OM
797 return EFI_SUCCESS;\r
798}\r
799\r
800/*\r
801 * UEFI Statistics() function\r
802 *\r
803 */\r
804EFI_STATUS\r
805EFIAPI\r
806SnpStatistics (\r
807 IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp,\r
808 IN BOOLEAN Reset,\r
809 IN OUT UINTN *StatSize,\r
810 OUT EFI_NETWORK_STATISTICS *Statistics\r
811 )\r
812{\r
0150e14d
RC
813 LAN9118_DRIVER *LanDriver;\r
814 EFI_STATUS Status;\r
46f2c53b
OM
815\r
816 LanDriver = INSTANCE_FROM_SNP_THIS (Snp);\r
817\r
818 DEBUG ((DEBUG_NET, "SnpStatistics()\n"));\r
819\r
820 // Check Snp instance\r
821 if (Snp == NULL) {\r
822 return EFI_INVALID_PARAMETER;\r
823 }\r
824\r
825 // Check that driver was started and initialised\r
826 if (Snp->Mode->State == EfiSimpleNetworkStarted) {\r
827 DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver not initialized\n"));\r
828 return EFI_DEVICE_ERROR;\r
829 } else if (Snp->Mode->State == EfiSimpleNetworkStopped) {\r
830 DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver in stopped state\n"));\r
831 return EFI_NOT_STARTED;\r
832 }\r
833\r
0150e14d
RC
834 //\r
835 // Do a reset if required. It is not clearly stated in the UEFI specification\r
836 // whether the reset has to be done before to copy the statistics in "Statictics"\r
837 // or after. It is a bit strange to do it before but that is what is expected by\r
838 // the SCT test on Statistics() with reset : "0x3de76704,0x4bf5,0x42cd,0x8c,0x89,\r
839 // 0x54,0x7e,0x4f,0xad,0x4f,0x24".\r
840 //\r
46f2c53b
OM
841 if (Reset) {\r
842 ZeroMem (&LanDriver->Stats, sizeof(EFI_NETWORK_STATISTICS));\r
843 }\r
844\r
0150e14d
RC
845 Status = EFI_SUCCESS;\r
846 if (StatSize == NULL) {\r
847 if (Statistics != NULL) {\r
848 return EFI_INVALID_PARAMETER;\r
849 }\r
850 } else {\r
851 if (Statistics == NULL) {\r
852 Status = EFI_BUFFER_TOO_SMALL;\r
853 } else {\r
854 // Fill in the statistics\r
855 CopyMem (\r
856 Statistics, &LanDriver->Stats,\r
857 MIN (*StatSize, sizeof (EFI_NETWORK_STATISTICS))\r
858 );\r
859 if (*StatSize < sizeof (EFI_NETWORK_STATISTICS)) {\r
860 Status = EFI_BUFFER_TOO_SMALL;\r
861 }\r
862 }\r
863 *StatSize = sizeof (EFI_NETWORK_STATISTICS);\r
46f2c53b
OM
864 }\r
865\r
0150e14d 866 return Status;\r
46f2c53b
OM
867}\r
868\r
869/*\r
870 * UEFI MCastIPtoMAC() function\r
871 *\r
872 */\r
873EFI_STATUS\r
874EFIAPI\r
875SnpMcastIptoMac (\r
876 IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp,\r
877 IN BOOLEAN IsIpv6,\r
878 IN EFI_IP_ADDRESS *Ip,\r
879 OUT EFI_MAC_ADDRESS *McastMac\r
880 )\r
881{\r
882 DEBUG ((DEBUG_NET, "SnpMcastIptoMac()\n"));\r
883\r
884 // Check Snp instance\r
885 if (Snp == NULL) {\r
886 return EFI_INVALID_PARAMETER;\r
887 }\r
888\r
889 // Check that driver was started and initialised\r
890 if (Snp->Mode->State == EfiSimpleNetworkStarted) {\r
891 DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver not initialized\n"));\r
892 return EFI_DEVICE_ERROR;\r
893 } else if (Snp->Mode->State == EfiSimpleNetworkStopped) {\r
894 DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver in stopped state\n"));\r
895 return EFI_NOT_STARTED;\r
896 }\r
897\r
898 // Check parameters\r
899 if ((McastMac == NULL) || (Ip == NULL)) {\r
900 return EFI_INVALID_PARAMETER;\r
901 }\r
902\r
903 // Make sure MAC address is empty\r
904 ZeroMem (McastMac, sizeof(EFI_MAC_ADDRESS));\r
905\r
906 // If we need ipv4 address\r
907 if (!IsIpv6) {\r
908 // Most significant 25 bits of a multicast HW address are set.\r
909 // 01-00-5E is the IPv4 Ethernet Multicast Address (see RFC 1112)\r
910 McastMac->Addr[0] = 0x01;\r
911 McastMac->Addr[1] = 0x00;\r
912 McastMac->Addr[2] = 0x5E;\r
913\r
914 // Lower 23 bits from ipv4 address\r
915 McastMac->Addr[3] = (Ip->v4.Addr[1] & 0x7F); // Clear the most significant bit (25th bit of MAC must be 0)\r
916 McastMac->Addr[4] = Ip->v4.Addr[2];\r
917 McastMac->Addr[5] = Ip->v4.Addr[3];\r
918 } else {\r
919 // Most significant 16 bits of multicast v6 HW address are set\r
920 // 33-33 is the IPv6 Ethernet Multicast Address (see RFC 2464)\r
921 McastMac->Addr[0] = 0x33;\r
922 McastMac->Addr[1] = 0x33;\r
923\r
924 // lower four octets are taken from ipv6 address\r
925 McastMac->Addr[2] = Ip->v6.Addr[8];\r
926 McastMac->Addr[3] = Ip->v6.Addr[9];\r
927 McastMac->Addr[4] = Ip->v6.Addr[10];\r
928 McastMac->Addr[5] = Ip->v6.Addr[11];\r
929 }\r
930\r
931 return EFI_SUCCESS;\r
932}\r
933\r
934/*\r
935 * UEFI NvData() function\r
936 *\r
937 */\r
938EFI_STATUS\r
939EFIAPI\r
940SnpNvData (\r
941 IN EFI_SIMPLE_NETWORK_PROTOCOL* pobj,\r
942 IN BOOLEAN read_write,\r
943 IN UINTN offset,\r
944 IN UINTN buff_size,\r
945 IN OUT VOID *data\r
946 )\r
947{\r
948 DEBUG ((DEBUG_NET, "SnpNvData()\n"));\r
949\r
950 return EFI_UNSUPPORTED;\r
951}\r
952\r
953\r
954/*\r
955 * UEFI GetStatus () function\r
956 *\r
957 */\r
958EFI_STATUS\r
959EFIAPI\r
960SnpGetStatus (\r
0150e14d
RC
961 IN EFI_SIMPLE_NETWORK_PROTOCOL *Snp,\r
962 OUT UINT32 *IrqStat OPTIONAL,\r
963 OUT VOID **TxBuff OPTIONAL\r
46f2c53b
OM
964 )\r
965{\r
966 UINT32 FifoInt;\r
967 EFI_STATUS Status;\r
968 UINTN NumTxStatusEntries;\r
969 UINT32 TxStatus;\r
970 UINT16 PacketTag;\r
971 UINT32 Interrupts;\r
972 LAN9118_DRIVER *LanDriver;\r
973\r
974 LanDriver = INSTANCE_FROM_SNP_THIS (Snp);\r
975\r
976 // Check preliminaries\r
977 if (Snp == NULL) {\r
978 return EFI_INVALID_PARAMETER;\r
979 }\r
980\r
0150e14d
RC
981 // Check that driver was started and initialised\r
982 if (Snp->Mode->State == EfiSimpleNetworkStarted) {\r
983 DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver not initialized\n"));\r
984 return EFI_DEVICE_ERROR;\r
985 } else if (Snp->Mode->State == EfiSimpleNetworkStopped) {\r
986 DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver in stopped state\n"));\r
46f2c53b
OM
987 return EFI_NOT_STARTED;\r
988 }\r
989\r
990 // Check and acknowledge TX Status interrupt (this will happen if the\r
991 // consumer of SNP does not call GetStatus.)\r
992 // TODO will we lose TxStatuses if this happens? Maybe in SnpTransmit we\r
993 // should check for it and dump the TX Status FIFO.\r
e68449c9 994 FifoInt = Lan9118MmioRead32 (LAN9118_FIFO_INT);\r
46f2c53b
OM
995\r
996 // Clear the TX Status FIFO Overflow\r
997 if ((FifoInt & INSTS_TXSO) == 0) {\r
998 FifoInt |= INSTS_TXSO;\r
e68449c9 999 Lan9118MmioWrite32 (LAN9118_FIFO_INT, FifoInt);\r
46f2c53b
OM
1000 }\r
1001\r
1002 // Read interrupt status if IrqStat is not NULL\r
1003 if (IrqStat != NULL) {\r
e52aee5d 1004 *IrqStat = 0;\r
46f2c53b
OM
1005\r
1006 // Check for receive interrupt\r
e68449c9 1007 if (Lan9118MmioRead32 (LAN9118_INT_STS) & INSTS_RSFL) { // Data moved from rx FIFO\r
46f2c53b 1008 *IrqStat |= EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT;\r
e68449c9 1009 Lan9118MmioWrite32 (LAN9118_INT_STS,INSTS_RSFL);\r
46f2c53b
OM
1010 }\r
1011\r
1012 // Check for transmit interrupt\r
e68449c9 1013 if (Lan9118MmioRead32 (LAN9118_INT_STS) & INSTS_TSFL) {\r
46f2c53b 1014 *IrqStat |= EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT;\r
e68449c9 1015 Lan9118MmioWrite32 (LAN9118_INT_STS,INSTS_TSFL);\r
46f2c53b
OM
1016 }\r
1017\r
1018 // Check for software interrupt\r
e68449c9 1019 if (Lan9118MmioRead32 (LAN9118_INT_STS) & INSTS_SW_INT) {\r
46f2c53b 1020 *IrqStat |= EFI_SIMPLE_NETWORK_SOFTWARE_INTERRUPT;\r
e68449c9 1021 Lan9118MmioWrite32 (LAN9118_INT_STS,INSTS_SW_INT);\r
46f2c53b
OM
1022 }\r
1023 }\r
1024\r
1025 // Check Status of transmitted packets\r
1026 // (We ignore TXSTATUS_NO_CA has it might happen in Full Duplex)\r
1027\r
e68449c9 1028 NumTxStatusEntries = Lan9118MmioRead32(LAN9118_TX_FIFO_INF) & TXFIFOINF_TXSUSED_MASK;\r
46f2c53b 1029 if (NumTxStatusEntries > 0) {\r
e68449c9 1030 TxStatus = Lan9118MmioRead32 (LAN9118_TX_STATUS);\r
46f2c53b
OM
1031 PacketTag = TxStatus >> 16;\r
1032 TxStatus = TxStatus & 0xFFFF;\r
a537c717 1033 if ((TxStatus & TXSTATUS_ES) && (TxStatus != (TXSTATUS_ES | TXSTATUS_NO_CA))) {\r
46f2c53b
OM
1034 DEBUG ((EFI_D_ERROR, "LAN9118: There was an error transmitting. TxStatus=0x%08x:", TxStatus));\r
1035 if (TxStatus & TXSTATUS_NO_CA) {\r
1036 DEBUG ((EFI_D_ERROR, "- No carrier\n"));\r
1037 }\r
1038 if (TxStatus & TXSTATUS_DEF) {\r
1039 DEBUG ((EFI_D_ERROR, "- Packet tx was deferred\n"));\r
1040 }\r
1041 if (TxStatus & TXSTATUS_EDEF) {\r
1042 DEBUG ((EFI_D_ERROR, "- Tx ended because of excessive deferral\n"));\r
1043 }\r
1044 if (TxStatus & TXSTATUS_ECOLL) {\r
1045 DEBUG ((EFI_D_ERROR, "- Tx ended because of Excessive Collisions\n"));\r
1046 }\r
1047 if (TxStatus & TXSTATUS_LCOLL) {\r
1048 DEBUG ((EFI_D_ERROR, "- Packet Tx aborted after coll window of 64 bytes\n"));\r
1049 }\r
1050 if (TxStatus & TXSTATUS_LOST_CA) {\r
1051 DEBUG ((EFI_D_ERROR, "- Lost carrier during Tx\n"));\r
1052 }\r
1053 return EFI_DEVICE_ERROR;\r
a537c717 1054 } else if (TxBuff != NULL) {\r
46f2c53b
OM
1055 LanDriver->Stats.TxTotalFrames += 1;\r
1056 *TxBuff = LanDriver->TxRing[PacketTag % LAN9118_TX_RING_NUM_ENTRIES];\r
1057 }\r
e117c894
MB
1058 } else if (TxBuff != NULL) {\r
1059 *TxBuff = NULL;\r
46f2c53b
OM
1060 }\r
1061\r
1062 // Check for a TX Error interrupt\r
e68449c9 1063 Interrupts = Lan9118MmioRead32 (LAN9118_INT_STS);\r
46f2c53b
OM
1064 if (Interrupts & INSTS_TXE) {\r
1065 DEBUG ((EFI_D_ERROR, "LAN9118: Transmitter error. Restarting..."));\r
1066\r
ac8f1e10 1067 // Software reset, the TXE interrupt is cleared by the reset.\r
42589b9a
OM
1068 Status = SoftReset (0, Snp);\r
1069 if (EFI_ERROR (Status)) {\r
46f2c53b
OM
1070 DEBUG ((EFI_D_ERROR, "\n\tSoft Reset Failed: Hardware Error\n"));\r
1071 return EFI_DEVICE_ERROR;\r
1072 }\r
1073\r
ac8f1e10
RC
1074 // Reactivate the LEDs\r
1075 Status = ConfigureHardware (HW_CONF_USE_LEDS, Snp);\r
1076 if (EFI_ERROR (Status)) {\r
1077 return Status;\r
1078 }\r
46f2c53b 1079\r
ac8f1e10
RC
1080 //\r
1081 // Restart the transmitter and if necessary the receiver.\r
1082 // Do not ask for FIFO reset as it has already been done\r
1083 // by SoftReset().\r
1084 //\r
46f2c53b 1085 StartTx (START_TX_MAC | START_TX_CFG, Snp);\r
ac8f1e10
RC
1086 if (Snp->Mode->ReceiveFilterSetting != 0) {\r
1087 StartRx (0, Snp);\r
1088 }\r
46f2c53b
OM
1089 }\r
1090\r
1091 // Update the media status\r
1092 Status = CheckLinkStatus (0, Snp);\r
1093 if (EFI_ERROR(Status)) {\r
1094 Snp->Mode->MediaPresent = FALSE;\r
1095 } else {\r
1096 Snp->Mode->MediaPresent = TRUE;\r
1097 }\r
1098\r
1099 return EFI_SUCCESS;\r
1100}\r
1101\r
1102\r
1103/*\r
1104 * UEFI Transmit() function\r
1105 *\r
1106 */\r
1107EFI_STATUS\r
1108EFIAPI\r
1109SnpTransmit (\r
1110 IN EFI_SIMPLE_NETWORK_PROTOCOL *Snp,\r
1111 IN UINTN HdrSize,\r
1112 IN UINTN BuffSize,\r
1113 IN VOID* Data,\r
1114 IN EFI_MAC_ADDRESS *SrcAddr OPTIONAL,\r
1115 IN EFI_MAC_ADDRESS *DstAddr OPTIONAL,\r
1116 IN UINT16 *Protocol OPTIONAL\r
1117 )\r
1118{\r
1119 LAN9118_DRIVER *LanDriver;\r
1120 UINT32 TxFreeSpace;\r
1121 UINT32 TxStatusSpace;\r
1122 INT32 Count;\r
1123 UINT32 CommandA;\r
1124 UINT32 CommandB;\r
1125 UINT16 LocalProtocol;\r
1126 UINT32 *LocalData;\r
1127 UINT16 PacketTag;\r
1128\r
1129#if defined(EVAL_PERFORMANCE)\r
1130 UINT64 Perf;\r
1131 UINT64 StartClock;\r
1132 UINT64 EndClock;\r
1133\r
1134 Perf = GetPerformanceCounterProperties (NULL, NULL);\r
1135 StartClock = GetPerformanceCounter ();\r
1136#endif\r
1137\r
1138 LanDriver = INSTANCE_FROM_SNP_THIS (Snp);\r
1139\r
1140 // Check preliminaries\r
1141 if ((Snp == NULL) || (Data == NULL)) {\r
1142 return EFI_INVALID_PARAMETER;\r
1143 }\r
0150e14d
RC
1144\r
1145 // Check that driver was started and initialised\r
1146 if (Snp->Mode->State == EfiSimpleNetworkStarted) {\r
1147 DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver not initialized\n"));\r
1148 return EFI_DEVICE_ERROR;\r
1149 } else if (Snp->Mode->State == EfiSimpleNetworkStopped) {\r
1150 DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver in stopped state\n"));\r
46f2c53b
OM
1151 return EFI_NOT_STARTED;\r
1152 }\r
1153\r
1154 // Ensure header is correct size if non-zero\r
1155 if (HdrSize) {\r
1156 if (HdrSize != Snp->Mode->MediaHeaderSize) {\r
1157 return EFI_INVALID_PARAMETER;\r
1158 }\r
1159\r
1160 if ((DstAddr == NULL) || (Protocol == NULL)) {\r
1161 return EFI_INVALID_PARAMETER;\r
1162 }\r
1163 }\r
1164\r
0150e14d
RC
1165 //\r
1166 // Check validity of BufferSize\r
1167 //\r
1168 if (BuffSize < Snp->Mode->MediaHeaderSize) {\r
1169 return EFI_BUFFER_TOO_SMALL;\r
1170 }\r
1171\r
46f2c53b
OM
1172 // Before transmitting check the link status\r
1173 /*if (CheckLinkStatus (0, Snp) < 0) {\r
1174 return EFI_NOT_READY;\r
1175 }*/\r
1176\r
1177 // Get DATA FIFO free space in bytes\r
1178 TxFreeSpace = TxDataFreeSpace (0, Snp);\r
1179 if (TxFreeSpace < BuffSize) {\r
1180 return EFI_NOT_READY;\r
1181 }\r
1182\r
1183 // Get STATUS FIFO used space in bytes\r
1184 TxStatusSpace = TxStatusUsedSpace (0, Snp);\r
1185 if (TxStatusSpace > 500) {\r
1186 return EFI_NOT_READY;\r
1187 }\r
1188\r
1189 // If DstAddr is not provided, get it from Buffer (we trust that the caller\r
1190 // has provided a well-formed frame).\r
1191 if (DstAddr == NULL) {\r
1192 DstAddr = (EFI_MAC_ADDRESS *) Data;\r
1193 }\r
1194\r
1195 // Check for the nature of the frame\r
1196 if ((DstAddr->Addr[0] & 0x1) == 1) {\r
1197 LanDriver->Stats.TxMulticastFrames += 1;\r
1198 } else {\r
1199 LanDriver->Stats.TxUnicastFrames += 1;\r
1200 }\r
1201\r
1202 // Check if broadcast\r
1203 if (DstAddr->Addr[0] == 0xFF) {\r
1204 LanDriver->Stats.TxBroadcastFrames += 1;\r
1205 }\r
1206\r
1207 PacketTag = LanDriver->NextPacketTag;\r
1208 LanDriver->NextPacketTag++;\r
1209\r
1210 if (HdrSize) {\r
1211\r
1212 // Format pointer\r
1213 LocalData = (UINT32*) Data;\r
1214 LocalProtocol = *Protocol;\r
1215\r
1216 // Create first buffer to pass to controller (for the header)\r
1217 CommandA = TX_CMD_A_FIRST_SEGMENT | TX_CMD_A_BUFF_SIZE (HdrSize);\r
1218 CommandB = TX_CMD_B_PACKET_TAG (PacketTag) | TX_CMD_B_PACKET_LENGTH (BuffSize);\r
1219\r
1220 // Write the commands first\r
e68449c9
MR
1221 Lan9118MmioWrite32 (LAN9118_TX_DATA, CommandA);\r
1222 Lan9118MmioWrite32 (LAN9118_TX_DATA, CommandB);\r
46f2c53b
OM
1223\r
1224 // Write the destination address\r
e68449c9 1225 Lan9118MmioWrite32 (LAN9118_TX_DATA,\r
46f2c53b
OM
1226 (DstAddr->Addr[0]) |\r
1227 (DstAddr->Addr[1] << 8) |\r
1228 (DstAddr->Addr[2] << 16) |\r
1229 (DstAddr->Addr[3] << 24)\r
1230 );\r
1231\r
e68449c9 1232 Lan9118MmioWrite32 (LAN9118_TX_DATA,\r
46f2c53b
OM
1233 (DstAddr->Addr[4]) |\r
1234 (DstAddr->Addr[5] << 8) |\r
1235 (SrcAddr->Addr[0] << 16) | // Write the Source Address\r
1236 (SrcAddr->Addr[1] << 24)\r
1237 );\r
1238\r
e68449c9 1239 Lan9118MmioWrite32 (LAN9118_TX_DATA,\r
46f2c53b
OM
1240 (SrcAddr->Addr[2]) |\r
1241 (SrcAddr->Addr[3] << 8) |\r
1242 (SrcAddr->Addr[4] << 16) |\r
1243 (SrcAddr->Addr[5] << 24)\r
1244 );\r
1245\r
1246 // Write the Protocol\r
e68449c9 1247 Lan9118MmioWrite32 (LAN9118_TX_DATA, (UINT32)(HTONS (LocalProtocol)));\r
46f2c53b
OM
1248\r
1249 // Next buffer is the payload\r
1250 CommandA = TX_CMD_A_LAST_SEGMENT | TX_CMD_A_BUFF_SIZE (BuffSize - HdrSize) | TX_CMD_A_COMPLETION_INT | TX_CMD_A_DATA_START_OFFSET (2); // 2 bytes beginning offset\r
1251\r
1252 // Write the commands\r
e68449c9
MR
1253 Lan9118MmioWrite32 (LAN9118_TX_DATA, CommandA);\r
1254 Lan9118MmioWrite32 (LAN9118_TX_DATA, CommandB);\r
46f2c53b
OM
1255\r
1256 // Write the payload\r
1257 for (Count = 0; Count < ((BuffSize + 3) >> 2) - 3; Count++) {\r
e68449c9 1258 Lan9118MmioWrite32 (LAN9118_TX_DATA, LocalData[Count + 3]);\r
46f2c53b
OM
1259 }\r
1260 } else {\r
1261 // Format pointer\r
1262 LocalData = (UINT32*) Data;\r
1263\r
1264 // Create a buffer to pass to controller\r
1265 CommandA = TX_CMD_A_FIRST_SEGMENT | TX_CMD_A_LAST_SEGMENT | TX_CMD_A_BUFF_SIZE (BuffSize) | TX_CMD_A_COMPLETION_INT;\r
1266 CommandB = TX_CMD_B_PACKET_TAG (PacketTag) | TX_CMD_B_PACKET_LENGTH (BuffSize);\r
1267\r
1268 // Write the commands first\r
e68449c9
MR
1269 Lan9118MmioWrite32 (LAN9118_TX_DATA, CommandA);\r
1270 Lan9118MmioWrite32 (LAN9118_TX_DATA, CommandB);\r
46f2c53b
OM
1271\r
1272 // Write all the data\r
1273 for (Count = 0; Count < ((BuffSize + 3) >> 2); Count++) {\r
e68449c9 1274 Lan9118MmioWrite32 (LAN9118_TX_DATA, LocalData[Count]);\r
46f2c53b
OM
1275 }\r
1276 }\r
1277\r
1278 // Save the address of the submitted packet so we can notify the consumer that\r
1279 // it has been sent in GetStatus. When the packet tag appears in the Tx Status\r
1280 // Fifo, we will return Buffer in the TxBuff parameter of GetStatus.\r
1281 LanDriver->TxRing[PacketTag % LAN9118_TX_RING_NUM_ENTRIES] = Data;\r
1282\r
1283#if defined(EVAL_PERFORMANCE)\r
1284 EndClock = GetPerformanceCounter ();\r
1285 DEBUG ((EFI_D_ERROR, "Time processing: %d counts @ %d Hz\n", StartClock - EndClock,Perf));\r
1286#endif\r
1287\r
1288 LanDriver->Stats.TxGoodFrames += 1;\r
1289\r
1290 return EFI_SUCCESS;\r
1291}\r
1292\r
1293\r
1294/*\r
1295 * UEFI Receive() function\r
1296 *\r
1297 */\r
1298EFI_STATUS\r
1299EFIAPI\r
1300SnpReceive (\r
1301 IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp,\r
1302 OUT UINTN *HdrSize OPTIONAL,\r
1303 IN OUT UINTN *BuffSize,\r
1304 OUT VOID *Data,\r
1305 OUT EFI_MAC_ADDRESS *SrcAddr OPTIONAL,\r
1306 OUT EFI_MAC_ADDRESS *DstAddr OPTIONAL,\r
1307 OUT UINT16 *Protocol OPTIONAL\r
1308 )\r
1309{\r
42589b9a 1310 LAN9118_DRIVER *LanDriver;\r
1130106e 1311 UINT32 IntSts;\r
42589b9a
OM
1312 UINT32 RxFifoStatus;\r
1313 UINT32 NumPackets;\r
1314 UINT32 RxCfgValue;\r
1315 UINT32 PLength; // Packet length\r
1316 UINT32 ReadLimit;\r
1317 UINT32 Count;\r
1318 UINT32 Padding;\r
1319 UINT32 *RawData;\r
46f2c53b
OM
1320 EFI_MAC_ADDRESS Dst;\r
1321 EFI_MAC_ADDRESS Src;\r
42589b9a
OM
1322 UINTN DroppedFrames;\r
1323 EFI_STATUS Status;\r
46f2c53b
OM
1324\r
1325 LanDriver = INSTANCE_FROM_SNP_THIS (Snp);\r
1326\r
1327#if defined(EVAL_PERFORMANCE)\r
1328 UINT64 Perf = GetPerformanceCounterProperties (NULL, NULL);\r
1329 UINT64 StartClock = GetPerformanceCounter ();\r
1330#endif\r
1331\r
1332 // Check preliminaries\r
0150e14d 1333 if ((Snp == NULL) || (Data == NULL) || (BuffSize == NULL)) {\r
46f2c53b
OM
1334 return EFI_INVALID_PARAMETER;\r
1335 }\r
1336\r
0150e14d
RC
1337 // Check that driver was started and initialised\r
1338 if (Snp->Mode->State == EfiSimpleNetworkStarted) {\r
1339 DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver not initialized\n"));\r
1340 return EFI_DEVICE_ERROR;\r
1341 } else if (Snp->Mode->State == EfiSimpleNetworkStopped) {\r
1342 DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver in stopped state\n"));\r
46f2c53b
OM
1343 return EFI_NOT_STARTED;\r
1344 }\r
1345\r
1130106e
RC
1346 //\r
1347 // If the receiver raised the RXE error bit, check if the receiver status\r
1348 // FIFO is full and if not just acknowledge the error. The two other\r
1349 // conditions to get a RXE error are :\r
1350 // . the RX data FIFO is read whereas being empty.\r
1351 // . the RX status FIFO is read whereas being empty.\r
1352 // The RX data and status FIFO are read by this driver only in the following\r
1353 // code of this function. After the readings, the RXE error bit is checked\r
1354 // and if raised, the controller is reset. Thus, at this point, we consider\r
1355 // that the only valid reason to get an RXE error is the receiver status\r
1356 // FIFO being full. And if this is not the case, we consider that this is\r
1357 // a spurious error and we just get rid of it. We experienced such 'spurious'\r
1358 // errors when running the driver on an A57 on Juno. No valid reason to\r
1359 // explain those errors has been found so far and everything seems to\r
1360 // work perfectly when they are just ignored.\r
1361 //\r
e68449c9 1362 IntSts = Lan9118MmioRead32 (LAN9118_INT_STS);\r
1130106e 1363 if ((IntSts & INSTS_RXE) && (!(IntSts & INSTS_RSFF))) {\r
e68449c9 1364 Lan9118MmioWrite32 (LAN9118_INT_STS, INSTS_RXE);\r
1130106e
RC
1365 }\r
1366\r
46f2c53b 1367 // Count dropped frames\r
e68449c9 1368 DroppedFrames = Lan9118MmioRead32 (LAN9118_RX_DROP);\r
46f2c53b
OM
1369 LanDriver->Stats.RxDroppedFrames += DroppedFrames;\r
1370\r
1371 NumPackets = RxStatusUsedSpace (0, Snp) / 4;\r
1372 if (!NumPackets) {\r
1373 return EFI_NOT_READY;\r
1374 }\r
1375\r
1376 // Read Rx Status (only if not empty)\r
e68449c9 1377 RxFifoStatus = Lan9118MmioRead32 (LAN9118_RX_STATUS);\r
46f2c53b
OM
1378 LanDriver->Stats.RxTotalFrames += 1;\r
1379\r
1380 // First check for errors\r
1381 if ((RxFifoStatus & RXSTATUS_MII_ERROR) ||\r
1382 (RxFifoStatus & RXSTATUS_RXW_TO) ||\r
1383 (RxFifoStatus & RXSTATUS_FTL) ||\r
1384 (RxFifoStatus & RXSTATUS_LCOLL) ||\r
1385 (RxFifoStatus & RXSTATUS_LE) ||\r
1386 (RxFifoStatus & RXSTATUS_DB))\r
1387 {\r
1388 DEBUG ((EFI_D_WARN, "Warning: There was an error on frame reception.\n"));\r
1389 return EFI_DEVICE_ERROR;\r
1390 }\r
1391\r
1392 // Check if we got a CRC error\r
1393 if (RxFifoStatus & RXSTATUS_CRC_ERROR) {\r
1394 DEBUG ((EFI_D_WARN, "Warning: Crc Error\n"));\r
1395 LanDriver->Stats.RxCrcErrorFrames += 1;\r
1396 LanDriver->Stats.RxDroppedFrames += 1;\r
1397 return EFI_DEVICE_ERROR;\r
1398 }\r
1399\r
1400 // Check if we got a runt frame\r
1401 if (RxFifoStatus & RXSTATUS_RUNT) {\r
1402 DEBUG ((EFI_D_WARN, "Warning: Runt Frame\n"));\r
1403 LanDriver->Stats.RxUndersizeFrames += 1;\r
1404 LanDriver->Stats.RxDroppedFrames += 1;\r
1405 return EFI_DEVICE_ERROR;\r
1406 }\r
1407\r
1408 // Check filtering status for this packet\r
1409 if (RxFifoStatus & RXSTATUS_FILT_FAIL) {\r
1410 DEBUG ((EFI_D_WARN, "Warning: Frame Failed Filtering\n"));\r
1411 // fast forward?\r
1412 }\r
1413\r
1414 // Check if we got a broadcast frame\r
1415 if (RxFifoStatus & RXSTATUS_BCF) {\r
1416 LanDriver->Stats.RxBroadcastFrames += 1;\r
1417 }\r
1418\r
1419 // Check if we got a multicast frame\r
1420 if (RxFifoStatus & RXSTATUS_MCF) {\r
1421 LanDriver->Stats.RxMulticastFrames += 1;\r
1422 }\r
1423\r
1424 // Check if we got a unicast frame\r
1425 if ((RxFifoStatus & RXSTATUS_BCF) && ((RxFifoStatus & RXSTATUS_MCF) == 0)) {\r
1426 LanDriver->Stats.RxUnicastFrames += 1;\r
1427 }\r
1428\r
1429 // Get the received packet length\r
1430 PLength = GET_RXSTATUS_PACKET_LENGTH(RxFifoStatus);\r
1431 LanDriver->Stats.RxTotalBytes += (PLength - 4);\r
1432\r
46f2c53b
OM
1433 // If padding is applied, read more DWORDs\r
1434 if (PLength % 4) {\r
1435 Padding = 4 - (PLength % 4);\r
1436 ReadLimit = (PLength + Padding)/4;\r
1437 } else {\r
1438 ReadLimit = PLength/4;\r
1439 Padding = 0;\r
1440 }\r
1441\r
f22e9658
OM
1442 // Check buffer size\r
1443 if (*BuffSize < (PLength + Padding)) {\r
1444 *BuffSize = PLength + Padding;\r
1445 return EFI_BUFFER_TOO_SMALL;\r
1446 }\r
1447\r
46f2c53b
OM
1448 // Set the amount of data to be transfered out of FIFO for THIS packet\r
1449 // This can be used to trigger an interrupt, and status can be checked\r
e68449c9 1450 RxCfgValue = Lan9118MmioRead32 (LAN9118_RX_CFG);\r
46f2c53b
OM
1451 RxCfgValue &= ~(RXCFG_RX_DMA_CNT_MASK);\r
1452 RxCfgValue |= RXCFG_RX_DMA_CNT (ReadLimit);\r
1453\r
1454 // Set end alignment to 4-bytes\r
1455 RxCfgValue &= ~(RXCFG_RX_END_ALIGN_MASK);\r
e68449c9 1456 Lan9118MmioWrite32 (LAN9118_RX_CFG, RxCfgValue);\r
46f2c53b
OM
1457\r
1458 // Update buffer size\r
1459 *BuffSize = PLength; // -4 bytes may be needed: Received in buffer as\r
1460 // 4 bytes longer than packet actually is, unless\r
1461 // packet is < 64 bytes\r
1462\r
1463 if (HdrSize != NULL)\r
1464 *HdrSize = Snp->Mode->MediaHeaderSize;\r
1465\r
1466 // Format the pointer\r
1467 RawData = (UINT32*)Data;\r
1468\r
1469 // Read Rx Packet\r
1470 for (Count = 0; Count < ReadLimit; Count++) {\r
e68449c9 1471 RawData[Count] = Lan9118MmioRead32 (LAN9118_RX_DATA);\r
46f2c53b
OM
1472 }\r
1473\r
1130106e
RC
1474 // Get the destination address\r
1475 if (DstAddr != NULL) {\r
1476 Dst.Addr[0] = (RawData[0] & 0xFF);\r
1477 Dst.Addr[1] = (RawData[0] & 0xFF00) >> 8;\r
1478 Dst.Addr[2] = (RawData[0] & 0xFF0000) >> 16;\r
1479 Dst.Addr[3] = (RawData[0] & 0xFF000000) >> 24;\r
1480 Dst.Addr[4] = (RawData[1] & 0xFF);\r
1481 Dst.Addr[5] = (RawData[1] & 0xFF00) >> 8;\r
1482 CopyMem (DstAddr, &Dst, NET_ETHER_ADDR_LEN);\r
1483 }\r
1484\r
1485 // Get the source address\r
1486 if (SrcAddr != NULL) {\r
1487 Src.Addr[0] = (RawData[1] & 0xFF0000) >> 16;\r
1488 Src.Addr[1] = (RawData[1] & 0xFF000000) >> 24;\r
1489 Src.Addr[2] = (RawData[2] & 0xFF);\r
1490 Src.Addr[3] = (RawData[2] & 0xFF00) >> 8;\r
1491 Src.Addr[4] = (RawData[2] & 0xFF0000) >> 16;\r
1492 Src.Addr[5] = (RawData[2] & 0xFF000000) >> 24;\r
1493 CopyMem (SrcAddr, &Src, NET_ETHER_ADDR_LEN);\r
1494 }\r
1495\r
1496 // Get the protocol\r
1497 if (Protocol != NULL) {\r
1498 *Protocol = NTOHS (RawData[3] & 0xFFFF);\r
1499 }\r
1500\r
46f2c53b 1501 // Check for Rx errors (worst possible error)\r
e68449c9 1502 if (Lan9118MmioRead32 (LAN9118_INT_STS) & INSTS_RXE) {\r
46f2c53b
OM
1503 DEBUG ((EFI_D_WARN, "Warning: Receiver Error. Restarting...\n"));\r
1504\r
ac8f1e10 1505 // Software reset, the RXE interrupt is cleared by the reset.\r
42589b9a
OM
1506 Status = SoftReset (0, Snp);\r
1507 if (EFI_ERROR (Status)) {\r
46f2c53b
OM
1508 DEBUG ((EFI_D_ERROR, "Error: Soft Reset Failed: Hardware Error.\n"));\r
1509 return EFI_DEVICE_ERROR;\r
1510 }\r
1511\r
ac8f1e10
RC
1512 // Reactivate the LEDs\r
1513 Status = ConfigureHardware (HW_CONF_USE_LEDS, Snp);\r
1514 if (EFI_ERROR (Status)) {\r
1515 return Status;\r
1516 }\r
46f2c53b 1517\r
ac8f1e10
RC
1518 //\r
1519 // Restart the receiver and the transmitter without reseting the FIFOs\r
1520 // as it has been done by SoftReset().\r
1521 //\r
46f2c53b 1522 StartRx (0, Snp);\r
ac8f1e10 1523 StartTx (START_TX_MAC | START_TX_CFG, Snp);\r
46f2c53b
OM
1524\r
1525 // Say that command could not be sent\r
1526 return EFI_DEVICE_ERROR;\r
1527 }\r
1528\r
46f2c53b
OM
1529#if defined(EVAL_PERFORMANCE)\r
1530 UINT64 EndClock = GetPerformanceCounter ();\r
1531 DEBUG ((EFI_D_ERROR, "Receive Time processing: %d counts @ %d Hz\n", StartClock - EndClock,Perf));\r
1532#endif\r
1533\r
1534 LanDriver->Stats.RxGoodFrames += 1;\r
1535\r
1536 return EFI_SUCCESS;\r
1537}\r