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