3 * Copyright (c) 2012-2014, ARM Limited. All rights reserved.
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
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.
15 #include "Lan9118Dxe.h"
19 MAC_ADDR_DEVICE_PATH Lan9118
;
20 EFI_DEVICE_PATH_PROTOCOL End
;
21 } LAN9118_DEVICE_PATH
;
23 LAN9118_DEVICE_PATH Lan9118PathTemplate
= {
26 MESSAGING_DEVICE_PATH
, MSG_MAC_ADDR_DP
,
27 { (UINT8
) (sizeof(MAC_ADDR_DEVICE_PATH
)), (UINT8
) ((sizeof(MAC_ADDR_DEVICE_PATH
)) >> 8) }
34 END_ENTIRE_DEVICE_PATH_SUBTYPE
,
35 { sizeof(EFI_DEVICE_PATH_PROTOCOL
), 0 }
40 ** Entry point for the LAN9118 driver
46 IN EFI_SYSTEM_TABLE
*SystemTable
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
;
56 // The PcdLan9118DxeBaseAddress PCD must be defined
57 ASSERT (PcdGet32 (PcdLan9118DxeBaseAddress
) != 0);
60 LanDriver
= AllocateZeroPool (sizeof (LAN9118_DRIVER
));
61 if (LanDriver
== NULL
) {
62 return EFI_OUT_OF_RESOURCES
;
64 Lan9118Path
= (LAN9118_DEVICE_PATH
*)AllocateCopyPool (sizeof (LAN9118_DEVICE_PATH
), &Lan9118PathTemplate
);
65 if (Lan9118Path
== NULL
) {
66 return EFI_OUT_OF_RESOURCES
;
69 // Initialize pointers
70 Snp
= &(LanDriver
->Snp
);
71 SnpMode
= &(LanDriver
->SnpMode
);
74 // Set the signature of the LAN Driver structure
75 LanDriver
->Signature
= LAN9118_SIGNATURE
;
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
;
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
;
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
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
;
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
));
118 // Set the interface type (1: Ethernet or 6: IEEE 802 Networks)
119 SnpMode
->IfType
= NET_IFTYPE_ETHERNET
;
121 // Mac address is changeable as it is loaded from erasable memory
122 SnpMode
->MacAddressChangeable
= TRUE
;
124 // Can only transmit one packet at a time
125 SnpMode
->MultipleTxSupported
= FALSE
;
127 // MediaPresent checks for cable connection and partner link
128 SnpMode
->MediaPresentSupported
= TRUE
;
129 SnpMode
->MediaPresent
= FALSE
;
131 // Set broadcast address
132 SetMem (&SnpMode
->BroadcastAddress
, sizeof (EFI_MAC_ADDRESS
), 0xFF);
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
;
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
;
145 // Initialise the protocol
146 ControllerHandle
= NULL
;
147 Status
= gBS
->InstallMultipleProtocolInterfaces (
149 &gEfiSimpleNetworkProtocolGuid
, Snp
,
150 &gEfiDevicePathProtocolGuid
, Lan9118Path
,
153 // Say what the status of loading the protocol structure is
154 if (EFI_ERROR(Status
)) {
155 FreePool (LanDriver
);
157 LanDriver
->ControllerHandle
= ControllerHandle
;
164 * UEFI Start() function
168 * @param Snp: A pointer to the EFI_SIMPLE_NETWORK_PROTOCOL instance.
172 * This function starts a network interface. If the network interface successfully starts, then
173 * EFI_SUCCESS will be returned.
178 IN EFI_SIMPLE_NETWORK_PROTOCOL
*Snp
181 // Check Snp instance
183 return EFI_INVALID_PARAMETER
;
187 if ((Snp
->Mode
->State
== EfiSimpleNetworkStarted
) ||
188 (Snp
->Mode
->State
== EfiSimpleNetworkInitialized
) ) {
189 return EFI_ALREADY_STARTED
;
193 Snp
->Mode
->State
= EfiSimpleNetworkStarted
;
198 * UEFI Stop() function
204 IN EFI_SIMPLE_NETWORK_PROTOCOL
* Snp
207 // Check Snp Instance
209 return EFI_INVALID_PARAMETER
;
212 // Check state of the driver
213 if (Snp
->Mode
->State
== EfiSimpleNetworkStopped
) {
214 return EFI_NOT_STARTED
;
217 // Stop the Tx and Rx
218 StopTx (STOP_TX_CFG
| STOP_TX_MAC
, Snp
);
222 switch (Snp
->Mode
->State
) {
223 case EfiSimpleNetworkStarted
:
224 case EfiSimpleNetworkInitialized
:
225 Snp
->Mode
->State
= EfiSimpleNetworkStopped
;
228 return EFI_DEVICE_ERROR
;
231 // Put the device into a power saving mode ?
236 // Allocated receive and transmit buffers
237 STATIC UINT32 gTxBuffer
= 0;
240 * UEFI Initialize() function
246 IN EFI_SIMPLE_NETWORK_PROTOCOL
* Snp
,
247 IN UINTN RxBufferSize OPTIONAL
,
248 IN UINTN TxBufferSize OPTIONAL
257 // Initialize variables
258 // Global variables to hold tx and rx FIFO allocation
261 // Check Snp Instance
263 return EFI_INVALID_PARAMETER
;
266 // First check that driver has not already been initialized
267 if (Snp
->Mode
->State
== EfiSimpleNetworkInitialized
) {
268 DEBUG ((EFI_D_WARN
, "LAN9118 Driver already initialized\n"));
271 if (Snp
->Mode
->State
== EfiSimpleNetworkStopped
) {
272 DEBUG ((EFI_D_WARN
, "LAN9118 Driver not started\n"));
273 return EFI_NOT_STARTED
;
276 // Initiate a PHY reset
277 Status
= PhySoftReset (PHY_RESET_PMT
| PHY_RESET_CHECK_LINK
, Snp
);
278 if (EFI_ERROR (Status
)) {
279 Snp
->Mode
->State
= EfiSimpleNetworkStopped
;
280 DEBUG ((EFI_D_WARN
, "Warning: Link not ready after TimeOut. Check ethernet cable\n"));
281 return EFI_NOT_STARTED
;
284 // Initiate a software reset
285 Status
= SoftReset (0, Snp
);
286 if (EFI_ERROR(Status
)) {
287 DEBUG ((EFI_D_WARN
, "Soft Reset Failed: Hardware Error\n"));
288 return EFI_DEVICE_ERROR
;
291 // Read the PM register
292 PmConf
= MmioRead32 (LAN9118_PMT_CTRL
);
294 // MPTCTRL_WOL_EN: Allow Wake-On-Lan to detect wake up frames or magic packets
295 // MPTCTRL_ED_EN: Allow energy detection to allow lowest power consumption mode
296 // MPTCTRL_PME_EN: Allow Power Management Events
298 PmConf
|= (MPTCTRL_WOL_EN
| MPTCTRL_ED_EN
| MPTCTRL_PME_EN
);
300 // Write the current configuration to the register
301 MmioWrite32 (LAN9118_PMT_CTRL
, PmConf
);
302 gBS
->Stall (LAN9118_STALL
);
303 gBS
->Stall (LAN9118_STALL
);
305 // Configure GPIO and HW
306 Status
= ConfigureHardware (HW_CONF_USE_LEDS
, Snp
);
307 if (EFI_ERROR(Status
)) {
311 // Assign the transmitter buffer size (default values)
312 TxStatusSize
= LAN9118_TX_STATUS_SIZE
;
313 RxStatusSize
= LAN9118_RX_STATUS_SIZE
;
315 // Check that a buff size was specified
316 if (TxBufferSize
> 0) {
317 if (RxBufferSize
== 0) {
318 RxBufferSize
= LAN9118_RX_DATA_SIZE
;
321 AllocResult
= ChangeFifoAllocation (
330 if (AllocResult
< 0) {
331 return EFI_OUT_OF_RESOURCES
;
335 // Do auto-negotiation if supported
336 Status
= AutoNegotiate (AUTO_NEGOTIATE_ADVERTISE_ALL
, Snp
);
337 if (EFI_ERROR(Status
)) {
338 DEBUG ((EFI_D_WARN
, "Lan9118: Auto Negociation not supported.\n"));
341 // Configure flow control depending on speed capabilities
342 Status
= ConfigureFlow (0, 0, 0, 0, Snp
);
343 if (EFI_ERROR(Status
)) {
347 // Enable the receiver and transmitter
348 Status
= StartRx (0, Snp
);
349 if (EFI_ERROR(Status
)) {
353 Status
= StartTx (START_TX_MAC
| START_TX_CFG
, Snp
);
354 if (EFI_ERROR(Status
)) {
358 // Now acknowledge all interrupts
359 MmioWrite32 (LAN9118_INT_STS
, ~0);
361 // Declare the driver as initialized
362 Snp
->Mode
->State
= EfiSimpleNetworkInitialized
;
368 * UEFI Reset () function
374 IN EFI_SIMPLE_NETWORK_PROTOCOL
* Snp
,
375 IN BOOLEAN Verification
387 // Check Snp Instance
389 return EFI_INVALID_PARAMETER
;
392 // First check that driver has not already been initialized
393 if (Snp
->Mode
->State
== EfiSimpleNetworkStarted
) {
394 DEBUG ((EFI_D_WARN
, "Warning: LAN9118 Driver not yet initialized\n"));
395 return EFI_DEVICE_ERROR
;
396 } else if (Snp
->Mode
->State
== EfiSimpleNetworkStopped
) {
397 DEBUG ((EFI_D_WARN
, "Warning: LAN9118 Driver not started\n"));
398 return EFI_NOT_STARTED
;
401 // Initiate a PHY reset
402 Status
= PhySoftReset (PHY_RESET_PMT
| PHY_RESET_CHECK_LINK
, Snp
);
403 if (EFI_ERROR (Status
)) {
404 Snp
->Mode
->State
= EfiSimpleNetworkStopped
;
405 return EFI_NOT_STARTED
;
408 // Initiate a software reset
409 ResetFlags
|= SOFT_RESET_CHECK_MAC_ADDR_LOAD
| SOFT_RESET_CLEAR_INT
;
412 ResetFlags
|= SOFT_RESET_SELF_TEST
;
415 Status
= SoftReset (ResetFlags
, Snp
);
416 if (EFI_ERROR (Status
)) {
417 DEBUG ((EFI_D_WARN
, "Warning: Soft Reset Failed: Hardware Error\n"));
418 return EFI_DEVICE_ERROR
;
421 // Read the PM register
422 PmConf
= MmioRead32 (LAN9118_PMT_CTRL
);
424 // MPTCTRL_WOL_EN: Allow Wake-On-Lan to detect wake up frames or magic packets
425 // MPTCTRL_ED_EN: Allow energy detection to allow lowest power consumption mode
426 // MPTCTRL_PME_EN: Allow Power Management Events
427 PmConf
|= (MPTCTRL_WOL_EN
| MPTCTRL_ED_EN
| MPTCTRL_PME_EN
);
429 // Write the current configuration to the register
430 MmioWrite32 (LAN9118_PMT_CTRL
, PmConf
);
431 gBS
->Stall (LAN9118_STALL
);
433 // Check that a buffer size was specified in SnpInitialize
434 if (gTxBuffer
!= 0) {
435 HwConf
= MmioRead32 (LAN9118_HW_CFG
); // Read the HW register
436 HwConf
&= ~HW_CFG_TX_FIFO_SIZE_MASK
; // Clear buffer bits first
437 HwConf
|= HW_CFG_TX_FIFO_SIZE(gTxBuffer
); // assign size chosen in SnpInitialize
439 MmioWrite32 (LAN9118_HW_CFG
, HwConf
); // Write the conf
440 gBS
->Stall (LAN9118_STALL
);
443 // Enable the receiver and transmitter and clear their contents
444 StartRx (START_RX_CLEAR
, Snp
);
445 StartTx (START_TX_MAC
| START_TX_CFG
| START_TX_CLEAR
, Snp
);
447 // Now acknowledge all interrupts
448 MmioWrite32 (LAN9118_INT_STS
, ~0);
454 * UEFI Shutdown () function
460 IN EFI_SIMPLE_NETWORK_PROTOCOL
* Snp
465 // Check Snp Instance
467 return EFI_INVALID_PARAMETER
;
470 // First check that driver has not already been initialized
471 if (Snp
->Mode
->State
== EfiSimpleNetworkStarted
) {
472 DEBUG ((EFI_D_WARN
, "Warning: LAN9118 Driver not yet initialized\n"));
473 return EFI_DEVICE_ERROR
;
474 } else if (Snp
->Mode
->State
== EfiSimpleNetworkStopped
) {
475 DEBUG ((EFI_D_WARN
, "Warning: LAN9118 Driver not started\n"));
476 return EFI_NOT_STARTED
;
479 // Initiate a PHY reset
480 Status
= PhySoftReset (PHY_RESET_PMT
, Snp
);
481 if (EFI_ERROR (Status
)) {
485 // Initiate a software reset
486 Status
= SoftReset (0, Snp
);
487 if (EFI_ERROR (Status
)) {
488 DEBUG ((EFI_D_WARN
, "Warning: Soft Reset Failed: Hardware Error\n"));
492 // Back to the started and thus not initialized state
493 Snp
->Mode
->State
= EfiSimpleNetworkStarted
;
499 Enable and/or disable the receive filters of the LAN9118
501 Please refer to the UEFI specification for the precedence rules among the
502 Enable, Disable and ResetMCastFilter parameters.
504 @param[in] Snp A pointer to the EFI_SIMPLE_NETWORK_PROTOCOL
506 @param[in] Enable A bit mask of receive filters to enable.
507 @param[in] Disable A bit mask of receive filters to disable.
508 @param[in] ResetMCastFilter Set to TRUE to reset the contents of the multicast
509 receive filters on the network interface to
510 their default values.
511 @param[in] MCastFilterCnt Number of multicast HW MAC addresses in the new
512 MCastFilter list. This value must be less than or
513 equal to the MCastFilterCnt field of
514 EFI_SIMPLE_NETWORK_MODE. This field is optional if
515 ResetMCastFilter is TRUE.
516 @param[in] MCastFilter A pointer to a list of new multicast receive
517 filter HW MAC addresses. This list will replace
518 any existing multicast HW MAC address list. This
519 field is optional if ResetMCastFilter is TRUE.
521 @retval EFI_SUCCESS The receive filters of the LAN9118 were updated.
522 @retval EFI_NOT_STARTED The LAN9118 has not been started.
523 @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE :
525 . Multicast is being enabled (the
526 EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST bit is set in
527 Enable, it is not set in Disable, and ResetMCastFilter
528 is FALSE) and MCastFilterCount is zero.
529 . Multicast is being enabled and MCastFilterCount is
530 greater than Snp->Mode->MaxMCastFilterCount.
531 . Multicast is being enabled and MCastFilter is NULL
532 . Multicast is being enabled and one or more of the
533 addresses in the MCastFilter list are not valid
534 multicast MAC addresses.
535 @retval EFI_DEVICE_ERROR The LAN9118 has been started but not initialized.
541 IN EFI_SIMPLE_NETWORK_PROTOCOL
*Snp
,
544 IN BOOLEAN ResetMCastFilter
,
545 IN UINTN MCastFilterCnt OPTIONAL
,
546 IN EFI_MAC_ADDRESS
*MCastFilter OPTIONAL
549 EFI_SIMPLE_NETWORK_MODE
*Mode
;
550 UINT32 MultHashTableHigh
;
551 UINT32 MultHashTableLow
;
556 EFI_MAC_ADDRESS
*Mac
;
558 // Check Snp Instance
560 return EFI_INVALID_PARAMETER
;
564 // Check that driver was started and initialised
565 if (Mode
->State
== EfiSimpleNetworkStarted
) {
566 DEBUG ((EFI_D_WARN
, "Warning: LAN9118 Driver not initialized\n"));
567 return EFI_DEVICE_ERROR
;
568 } else if (Mode
->State
== EfiSimpleNetworkStopped
) {
569 DEBUG ((EFI_D_WARN
, "Warning: LAN9118 Driver in stopped state\n"));
570 return EFI_NOT_STARTED
;
573 if ((Enable
& (~Mode
->ReceiveFilterMask
)) ||
574 (Disable
& (~Mode
->ReceiveFilterMask
)) ) {
575 return EFI_INVALID_PARAMETER
;
579 // Check the validity of the multicast setting and compute the
580 // hash values of the multicast mac addresses to listen to.
583 MultHashTableHigh
= 0;
584 MultHashTableLow
= 0;
585 if ((!ResetMCastFilter
) &&
586 ((Disable
& EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST
) == 0) &&
587 ((Enable
& EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST
) != 0) ) {
588 if ((MCastFilterCnt
== 0) ||
589 (MCastFilterCnt
> Mode
->MaxMCastFilterCount
) ||
590 (MCastFilter
== NULL
) ) {
591 return EFI_INVALID_PARAMETER
;
594 // Check the validity of all multicast addresses before to change
597 for (Count
= 0; Count
< MCastFilterCnt
; Count
++) {
598 if ((MCastFilter
[Count
].Addr
[0] & 1) == 0) {
599 return EFI_INVALID_PARAMETER
;
604 // Go through each filter address and set appropriate bits on hash table
606 for (Count
= 0; Count
< MCastFilterCnt
; Count
++) {
607 Mac
= &(MCastFilter
[Count
]);
608 CopyMem (&Mode
->MCastFilter
[Count
], Mac
, sizeof(EFI_MAC_ADDRESS
));
610 Crc
= GenEtherCrc32 (Mac
, NET_ETHER_ADDR_LEN
);
611 //gBS->CalculateCrc32 ((VOID*)&Mfilter[Count],6,&Crc); <-- doesn't work as desired
614 // The most significant 6 bits of the MAC address CRC constitute the hash
615 // value of the MAC address.
617 HashValue
= (Crc
>> 26) & 0x3F;
619 // Select hashlow register if MSB is not set
620 if ((HashValue
& 0x20) == 0) {
621 MultHashTableLow
|= (1 << HashValue
);
623 MultHashTableHigh
|= (1 << (HashValue
& 0x1F));
626 Mode
->MCastFilterCount
= MCastFilterCnt
;
627 } else if (ResetMCastFilter
) {
628 Mode
->MCastFilterCount
= 0;
630 MultHashTableLow
= IndirectMACRead32 (INDIRECT_MAC_INDEX_HASHL
);
631 MultHashTableHigh
= IndirectMACRead32 (INDIRECT_MAC_INDEX_HASHH
);
635 // Write the mask of the selected hash values for the multicast filtering.
636 // The two masks are set to zero if the multicast filtering is not enabled.
638 IndirectMACWrite32 (INDIRECT_MAC_INDEX_HASHL
, MultHashTableLow
);
639 IndirectMACWrite32 (INDIRECT_MAC_INDEX_HASHH
, MultHashTableHigh
);
641 // Read MAC controller
642 MacCSRValue
= IndirectMACRead32 (INDIRECT_MAC_INDEX_CR
);
644 // Set the options for the MAC_CSR
645 if (Enable
& EFI_SIMPLE_NETWORK_RECEIVE_UNICAST
) {
647 DEBUG ((DEBUG_NET
, "Allowing Unicast Frame Reception\n"));
650 if (Disable
& EFI_SIMPLE_NETWORK_RECEIVE_UNICAST
) {
652 DEBUG ((DEBUG_NET
, "Disabling Unicast Frame Reception\n"));
655 if (Enable
& EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST
) {
656 MacCSRValue
|= MACCR_HPFILT
;
657 DEBUG ((DEBUG_NET
, "Allowing Multicast Frame Reception\n"));
660 if (Disable
& EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST
) {
661 MacCSRValue
&= ~MACCR_HPFILT
;
662 DEBUG ((DEBUG_NET
, "Disabling Multicast Frame Reception\n"));
665 if (Enable
& EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST
) {
666 MacCSRValue
&= ~(MACCR_BCAST
);
667 DEBUG ((DEBUG_NET
, "Allowing Broadcast Frame Reception\n"));
670 if (Disable
& EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST
) {
671 MacCSRValue
|= MACCR_BCAST
;
672 DEBUG ((DEBUG_NET
, "Disabling Broadcast Frame Reception\n"));
675 if (Enable
& EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS
) {
676 MacCSRValue
|= MACCR_PRMS
;
677 DEBUG ((DEBUG_NET
, "Enabling Promiscuous Mode\n"));
680 if (Disable
& EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS
) {
681 MacCSRValue
&= ~MACCR_PRMS
;
682 DEBUG ((DEBUG_NET
, "Disabling Promiscuous Mode\n"));
685 if (Enable
& EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST
) {
686 MacCSRValue
|= (MACCR_HPFILT
| MACCR_PRMS
);
687 DEBUG ((DEBUG_NET
, "Enabling Promiscuous Multicast Mode\n"));
690 if (Disable
& EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST
) {
691 MacCSRValue
&= ~(MACCR_HPFILT
| MACCR_PRMS
);
692 DEBUG ((DEBUG_NET
, "Disabling Promiscuous Multicast Mode\n"));
695 // Write the options to the MAC_CSR
696 IndirectMACWrite32 (INDIRECT_MAC_INDEX_CR
, MacCSRValue
);
697 gBS
->Stall (LAN9118_STALL
);
703 Modify of reset the current station address
705 @param[in] Snp A pointer to the EFI_SIMPLE_NETWORK_PROTOCOL
707 @param[in] Reset Flag used to reset the station address to the
708 LAN9118's permanent address.
709 @param[in] New New station address to be used for the network interface.
711 @retval EFI_SUCCESS The LAN9118's station address was updated.
712 @retval EFI_NOT_STARTED The LAN9118 has not been started.
713 @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE :
714 . The "New" station address is invalid.
715 . "Reset" is FALSE and "New" is NULL.
716 @retval EFI_DEVICE_ERROR The LAN9118 has been started but not initialized.
722 IN EFI_SIMPLE_NETWORK_PROTOCOL
*Snp
,
724 IN EFI_MAC_ADDRESS
*New
728 UINT8 PermAddr
[NET_ETHER_ADDR_LEN
];
730 DEBUG ((DEBUG_NET
, "SnpStationAddress()\n"));
732 // Check Snp instance
734 return EFI_INVALID_PARAMETER
;
737 // Check that driver was started and initialised
738 if (Snp
->Mode
->State
== EfiSimpleNetworkStarted
) {
739 DEBUG ((EFI_D_WARN
, "Warning: LAN9118 Driver not initialized\n"));
740 return EFI_DEVICE_ERROR
;
741 } else if (Snp
->Mode
->State
== EfiSimpleNetworkStopped
) {
742 DEBUG ((EFI_D_WARN
, "Warning: LAN9118 Driver in stopped state\n"));
743 return EFI_NOT_STARTED
;
746 // Get the Permanent MAC address if need reset
748 // Try using EEPROM first. Read the first byte of data from EEPROM at the address 0x0
749 if ((IndirectEEPROMRead32 (0) & 0xFF) == EEPROM_EXTERNAL_SERIAL_EEPROM
) {
750 for (Count
= 0; Count
< NET_ETHER_ADDR_LEN
; Count
++) {
751 PermAddr
[Count
] = IndirectEEPROMRead32 (Count
+ 1);
753 New
= (EFI_MAC_ADDRESS
*) PermAddr
;
754 Lan9118SetMacAddress ((EFI_MAC_ADDRESS
*) PermAddr
, Snp
);
756 DEBUG ((EFI_D_ERROR
, "Lan9118: Warning: No valid MAC address in EEPROM, using fallback\n"));
757 New
= (EFI_MAC_ADDRESS
*) (FixedPcdGet64 (PcdLan9118DefaultMacAddress
));
760 // Otherwise use the specified new MAC address
762 return EFI_INVALID_PARAMETER
;
765 // If it is a multicast address, it is not valid.
767 if (New
->Addr
[0] & 0x01) {
768 return EFI_INVALID_PARAMETER
;
773 Lan9118SetMacAddress (New
, Snp
);
779 * UEFI Statistics() function
785 IN EFI_SIMPLE_NETWORK_PROTOCOL
* Snp
,
787 IN OUT UINTN
*StatSize
,
788 OUT EFI_NETWORK_STATISTICS
*Statistics
791 LAN9118_DRIVER
*LanDriver
;
794 LanDriver
= INSTANCE_FROM_SNP_THIS (Snp
);
796 DEBUG ((DEBUG_NET
, "SnpStatistics()\n"));
798 // Check Snp instance
800 return EFI_INVALID_PARAMETER
;
803 // Check that driver was started and initialised
804 if (Snp
->Mode
->State
== EfiSimpleNetworkStarted
) {
805 DEBUG ((EFI_D_WARN
, "Warning: LAN9118 Driver not initialized\n"));
806 return EFI_DEVICE_ERROR
;
807 } else if (Snp
->Mode
->State
== EfiSimpleNetworkStopped
) {
808 DEBUG ((EFI_D_WARN
, "Warning: LAN9118 Driver in stopped state\n"));
809 return EFI_NOT_STARTED
;
813 // Do a reset if required. It is not clearly stated in the UEFI specification
814 // whether the reset has to be done before to copy the statistics in "Statictics"
815 // or after. It is a bit strange to do it before but that is what is expected by
816 // the SCT test on Statistics() with reset : "0x3de76704,0x4bf5,0x42cd,0x8c,0x89,
817 // 0x54,0x7e,0x4f,0xad,0x4f,0x24".
820 ZeroMem (&LanDriver
->Stats
, sizeof(EFI_NETWORK_STATISTICS
));
823 Status
= EFI_SUCCESS
;
824 if (StatSize
== NULL
) {
825 if (Statistics
!= NULL
) {
826 return EFI_INVALID_PARAMETER
;
829 if (Statistics
== NULL
) {
830 Status
= EFI_BUFFER_TOO_SMALL
;
832 // Fill in the statistics
834 Statistics
, &LanDriver
->Stats
,
835 MIN (*StatSize
, sizeof (EFI_NETWORK_STATISTICS
))
837 if (*StatSize
< sizeof (EFI_NETWORK_STATISTICS
)) {
838 Status
= EFI_BUFFER_TOO_SMALL
;
841 *StatSize
= sizeof (EFI_NETWORK_STATISTICS
);
848 * UEFI MCastIPtoMAC() function
854 IN EFI_SIMPLE_NETWORK_PROTOCOL
* Snp
,
856 IN EFI_IP_ADDRESS
*Ip
,
857 OUT EFI_MAC_ADDRESS
*McastMac
860 DEBUG ((DEBUG_NET
, "SnpMcastIptoMac()\n"));
862 // Check Snp instance
864 return EFI_INVALID_PARAMETER
;
867 // Check that driver was started and initialised
868 if (Snp
->Mode
->State
== EfiSimpleNetworkStarted
) {
869 DEBUG ((EFI_D_WARN
, "Warning: LAN9118 Driver not initialized\n"));
870 return EFI_DEVICE_ERROR
;
871 } else if (Snp
->Mode
->State
== EfiSimpleNetworkStopped
) {
872 DEBUG ((EFI_D_WARN
, "Warning: LAN9118 Driver in stopped state\n"));
873 return EFI_NOT_STARTED
;
877 if ((McastMac
== NULL
) || (Ip
== NULL
)) {
878 return EFI_INVALID_PARAMETER
;
881 // Make sure MAC address is empty
882 ZeroMem (McastMac
, sizeof(EFI_MAC_ADDRESS
));
884 // If we need ipv4 address
886 // Most significant 25 bits of a multicast HW address are set.
887 // 01-00-5E is the IPv4 Ethernet Multicast Address (see RFC 1112)
888 McastMac
->Addr
[0] = 0x01;
889 McastMac
->Addr
[1] = 0x00;
890 McastMac
->Addr
[2] = 0x5E;
892 // Lower 23 bits from ipv4 address
893 McastMac
->Addr
[3] = (Ip
->v4
.Addr
[1] & 0x7F); // Clear the most significant bit (25th bit of MAC must be 0)
894 McastMac
->Addr
[4] = Ip
->v4
.Addr
[2];
895 McastMac
->Addr
[5] = Ip
->v4
.Addr
[3];
897 // Most significant 16 bits of multicast v6 HW address are set
898 // 33-33 is the IPv6 Ethernet Multicast Address (see RFC 2464)
899 McastMac
->Addr
[0] = 0x33;
900 McastMac
->Addr
[1] = 0x33;
902 // lower four octets are taken from ipv6 address
903 McastMac
->Addr
[2] = Ip
->v6
.Addr
[8];
904 McastMac
->Addr
[3] = Ip
->v6
.Addr
[9];
905 McastMac
->Addr
[4] = Ip
->v6
.Addr
[10];
906 McastMac
->Addr
[5] = Ip
->v6
.Addr
[11];
913 * UEFI NvData() function
919 IN EFI_SIMPLE_NETWORK_PROTOCOL
* pobj
,
920 IN BOOLEAN read_write
,
926 DEBUG ((DEBUG_NET
, "SnpNvData()\n"));
928 return EFI_UNSUPPORTED
;
933 * UEFI GetStatus () function
939 IN EFI_SIMPLE_NETWORK_PROTOCOL
*Snp
,
940 OUT UINT32
*IrqStat OPTIONAL
,
941 OUT VOID
**TxBuff OPTIONAL
946 UINTN NumTxStatusEntries
;
950 LAN9118_DRIVER
*LanDriver
;
952 LanDriver
= INSTANCE_FROM_SNP_THIS (Snp
);
954 // Check preliminaries
956 return EFI_INVALID_PARAMETER
;
959 // Check that driver was started and initialised
960 if (Snp
->Mode
->State
== EfiSimpleNetworkStarted
) {
961 DEBUG ((EFI_D_WARN
, "Warning: LAN9118 Driver not initialized\n"));
962 return EFI_DEVICE_ERROR
;
963 } else if (Snp
->Mode
->State
== EfiSimpleNetworkStopped
) {
964 DEBUG ((EFI_D_WARN
, "Warning: LAN9118 Driver in stopped state\n"));
965 return EFI_NOT_STARTED
;
968 // Check and acknowledge TX Status interrupt (this will happen if the
969 // consumer of SNP does not call GetStatus.)
970 // TODO will we lose TxStatuses if this happens? Maybe in SnpTransmit we
971 // should check for it and dump the TX Status FIFO.
972 FifoInt
= MmioRead32 (LAN9118_FIFO_INT
);
974 // Clear the TX Status FIFO Overflow
975 if ((FifoInt
& INSTS_TXSO
) == 0) {
976 FifoInt
|= INSTS_TXSO
;
977 MmioWrite32 (LAN9118_FIFO_INT
, FifoInt
);
980 // Read interrupt status if IrqStat is not NULL
981 if (IrqStat
!= NULL
) {
983 // Check for receive interrupt
984 if (MmioRead32 (LAN9118_INT_STS
) & INSTS_RSFL
) { // Data moved from rx FIFO
985 *IrqStat
|= EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT
;
986 MmioWrite32 (LAN9118_INT_STS
,INSTS_RSFL
);
988 *IrqStat
&= ~EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT
;
991 // Check for transmit interrupt
992 if (MmioRead32 (LAN9118_INT_STS
) & INSTS_TSFL
) {
993 *IrqStat
|= EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT
;
994 MmioWrite32 (LAN9118_INT_STS
,INSTS_TSFL
);
996 *IrqStat
&= ~EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT
;
999 // Check for software interrupt
1000 if (MmioRead32 (LAN9118_INT_STS
) & INSTS_SW_INT
) {
1001 *IrqStat
|= EFI_SIMPLE_NETWORK_SOFTWARE_INTERRUPT
;
1002 MmioWrite32 (LAN9118_INT_STS
,INSTS_SW_INT
);
1004 *IrqStat
&= ~EFI_SIMPLE_NETWORK_SOFTWARE_INTERRUPT
;
1008 // Check Status of transmitted packets
1009 // (We ignore TXSTATUS_NO_CA has it might happen in Full Duplex)
1011 NumTxStatusEntries
= MmioRead32(LAN9118_TX_FIFO_INF
) & TXFIFOINF_TXSUSED_MASK
;
1012 if (NumTxStatusEntries
> 0) {
1013 TxStatus
= MmioRead32 (LAN9118_TX_STATUS
);
1014 PacketTag
= TxStatus
>> 16;
1015 TxStatus
= TxStatus
& 0xFFFF;
1016 if ((TxStatus
& TXSTATUS_ES
) && (TxStatus
!= (TXSTATUS_ES
| TXSTATUS_NO_CA
))) {
1017 DEBUG ((EFI_D_ERROR
, "LAN9118: There was an error transmitting. TxStatus=0x%08x:", TxStatus
));
1018 if (TxStatus
& TXSTATUS_NO_CA
) {
1019 DEBUG ((EFI_D_ERROR
, "- No carrier\n"));
1021 if (TxStatus
& TXSTATUS_DEF
) {
1022 DEBUG ((EFI_D_ERROR
, "- Packet tx was deferred\n"));
1024 if (TxStatus
& TXSTATUS_EDEF
) {
1025 DEBUG ((EFI_D_ERROR
, "- Tx ended because of excessive deferral\n"));
1027 if (TxStatus
& TXSTATUS_ECOLL
) {
1028 DEBUG ((EFI_D_ERROR
, "- Tx ended because of Excessive Collisions\n"));
1030 if (TxStatus
& TXSTATUS_LCOLL
) {
1031 DEBUG ((EFI_D_ERROR
, "- Packet Tx aborted after coll window of 64 bytes\n"));
1033 if (TxStatus
& TXSTATUS_LOST_CA
) {
1034 DEBUG ((EFI_D_ERROR
, "- Lost carrier during Tx\n"));
1036 return EFI_DEVICE_ERROR
;
1037 } else if (TxBuff
!= NULL
) {
1038 LanDriver
->Stats
.TxTotalFrames
+= 1;
1039 *TxBuff
= LanDriver
->TxRing
[PacketTag
% LAN9118_TX_RING_NUM_ENTRIES
];
1043 // Check for a TX Error interrupt
1044 Interrupts
= MmioRead32 (LAN9118_INT_STS
);
1045 if (Interrupts
& INSTS_TXE
) {
1046 DEBUG ((EFI_D_ERROR
, "LAN9118: Transmitter error. Restarting..."));
1048 // Initiate a software reset
1049 Status
= SoftReset (0, Snp
);
1050 if (EFI_ERROR (Status
)) {
1051 DEBUG ((EFI_D_ERROR
, "\n\tSoft Reset Failed: Hardware Error\n"));
1052 return EFI_DEVICE_ERROR
;
1055 // Acknowledge the TXE
1056 MmioWrite32 (LAN9118_INT_STS
, INSTS_TXE
);
1057 gBS
->Stall (LAN9118_STALL
);
1059 // Restart the transmitter
1060 StartTx (START_TX_MAC
| START_TX_CFG
, Snp
);
1063 // Update the media status
1064 Status
= CheckLinkStatus (0, Snp
);
1065 if (EFI_ERROR(Status
)) {
1066 Snp
->Mode
->MediaPresent
= FALSE
;
1068 Snp
->Mode
->MediaPresent
= TRUE
;
1076 * UEFI Transmit() function
1082 IN EFI_SIMPLE_NETWORK_PROTOCOL
*Snp
,
1086 IN EFI_MAC_ADDRESS
*SrcAddr OPTIONAL
,
1087 IN EFI_MAC_ADDRESS
*DstAddr OPTIONAL
,
1088 IN UINT16
*Protocol OPTIONAL
1091 LAN9118_DRIVER
*LanDriver
;
1093 UINT32 TxStatusSpace
;
1097 UINT16 LocalProtocol
;
1101 #if defined(EVAL_PERFORMANCE)
1106 Perf
= GetPerformanceCounterProperties (NULL
, NULL
);
1107 StartClock
= GetPerformanceCounter ();
1110 LanDriver
= INSTANCE_FROM_SNP_THIS (Snp
);
1112 // Check preliminaries
1113 if ((Snp
== NULL
) || (Data
== NULL
)) {
1114 return EFI_INVALID_PARAMETER
;
1117 // Check that driver was started and initialised
1118 if (Snp
->Mode
->State
== EfiSimpleNetworkStarted
) {
1119 DEBUG ((EFI_D_WARN
, "Warning: LAN9118 Driver not initialized\n"));
1120 return EFI_DEVICE_ERROR
;
1121 } else if (Snp
->Mode
->State
== EfiSimpleNetworkStopped
) {
1122 DEBUG ((EFI_D_WARN
, "Warning: LAN9118 Driver in stopped state\n"));
1123 return EFI_NOT_STARTED
;
1126 // Ensure header is correct size if non-zero
1128 if (HdrSize
!= Snp
->Mode
->MediaHeaderSize
) {
1129 return EFI_INVALID_PARAMETER
;
1132 if ((DstAddr
== NULL
) || (Protocol
== NULL
)) {
1133 return EFI_INVALID_PARAMETER
;
1138 // Check validity of BufferSize
1140 if (BuffSize
< Snp
->Mode
->MediaHeaderSize
) {
1141 return EFI_BUFFER_TOO_SMALL
;
1144 // Before transmitting check the link status
1145 /*if (CheckLinkStatus (0, Snp) < 0) {
1146 return EFI_NOT_READY;
1149 // Get DATA FIFO free space in bytes
1150 TxFreeSpace
= TxDataFreeSpace (0, Snp
);
1151 if (TxFreeSpace
< BuffSize
) {
1152 return EFI_NOT_READY
;
1155 // Get STATUS FIFO used space in bytes
1156 TxStatusSpace
= TxStatusUsedSpace (0, Snp
);
1157 if (TxStatusSpace
> 500) {
1158 return EFI_NOT_READY
;
1161 // If DstAddr is not provided, get it from Buffer (we trust that the caller
1162 // has provided a well-formed frame).
1163 if (DstAddr
== NULL
) {
1164 DstAddr
= (EFI_MAC_ADDRESS
*) Data
;
1167 // Check for the nature of the frame
1168 if ((DstAddr
->Addr
[0] & 0x1) == 1) {
1169 LanDriver
->Stats
.TxMulticastFrames
+= 1;
1171 LanDriver
->Stats
.TxUnicastFrames
+= 1;
1174 // Check if broadcast
1175 if (DstAddr
->Addr
[0] == 0xFF) {
1176 LanDriver
->Stats
.TxBroadcastFrames
+= 1;
1179 PacketTag
= LanDriver
->NextPacketTag
;
1180 LanDriver
->NextPacketTag
++;
1185 LocalData
= (UINT32
*) Data
;
1186 LocalProtocol
= *Protocol
;
1188 // Create first buffer to pass to controller (for the header)
1189 CommandA
= TX_CMD_A_FIRST_SEGMENT
| TX_CMD_A_BUFF_SIZE (HdrSize
);
1190 CommandB
= TX_CMD_B_PACKET_TAG (PacketTag
) | TX_CMD_B_PACKET_LENGTH (BuffSize
);
1192 // Write the commands first
1193 MmioWrite32 (LAN9118_TX_DATA
, CommandA
);
1194 MmioWrite32 (LAN9118_TX_DATA
, CommandB
);
1196 // Write the destination address
1197 MmioWrite32 (LAN9118_TX_DATA
,
1198 (DstAddr
->Addr
[0]) |
1199 (DstAddr
->Addr
[1] << 8) |
1200 (DstAddr
->Addr
[2] << 16) |
1201 (DstAddr
->Addr
[3] << 24)
1204 MmioWrite32 (LAN9118_TX_DATA
,
1205 (DstAddr
->Addr
[4]) |
1206 (DstAddr
->Addr
[5] << 8) |
1207 (SrcAddr
->Addr
[0] << 16) | // Write the Source Address
1208 (SrcAddr
->Addr
[1] << 24)
1211 MmioWrite32 (LAN9118_TX_DATA
,
1212 (SrcAddr
->Addr
[2]) |
1213 (SrcAddr
->Addr
[3] << 8) |
1214 (SrcAddr
->Addr
[4] << 16) |
1215 (SrcAddr
->Addr
[5] << 24)
1218 // Write the Protocol
1219 MmioWrite32 (LAN9118_TX_DATA
, (UINT32
)(HTONS (LocalProtocol
)));
1221 // Next buffer is the payload
1222 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
1224 // Write the commands
1225 MmioWrite32 (LAN9118_TX_DATA
, CommandA
);
1226 MmioWrite32 (LAN9118_TX_DATA
, CommandB
);
1228 // Write the payload
1229 for (Count
= 0; Count
< ((BuffSize
+ 3) >> 2) - 3; Count
++) {
1230 MmioWrite32 (LAN9118_TX_DATA
, LocalData
[Count
+ 3]);
1234 LocalData
= (UINT32
*) Data
;
1236 // Create a buffer to pass to controller
1237 CommandA
= TX_CMD_A_FIRST_SEGMENT
| TX_CMD_A_LAST_SEGMENT
| TX_CMD_A_BUFF_SIZE (BuffSize
) | TX_CMD_A_COMPLETION_INT
;
1238 CommandB
= TX_CMD_B_PACKET_TAG (PacketTag
) | TX_CMD_B_PACKET_LENGTH (BuffSize
);
1240 // Write the commands first
1241 MmioWrite32 (LAN9118_TX_DATA
, CommandA
);
1242 MmioWrite32 (LAN9118_TX_DATA
, CommandB
);
1244 // Write all the data
1245 for (Count
= 0; Count
< ((BuffSize
+ 3) >> 2); Count
++) {
1246 MmioWrite32 (LAN9118_TX_DATA
, LocalData
[Count
]);
1250 // Save the address of the submitted packet so we can notify the consumer that
1251 // it has been sent in GetStatus. When the packet tag appears in the Tx Status
1252 // Fifo, we will return Buffer in the TxBuff parameter of GetStatus.
1253 LanDriver
->TxRing
[PacketTag
% LAN9118_TX_RING_NUM_ENTRIES
] = Data
;
1255 #if defined(EVAL_PERFORMANCE)
1256 EndClock
= GetPerformanceCounter ();
1257 DEBUG ((EFI_D_ERROR
, "Time processing: %d counts @ %d Hz\n", StartClock
- EndClock
,Perf
));
1260 LanDriver
->Stats
.TxGoodFrames
+= 1;
1267 * UEFI Receive() function
1273 IN EFI_SIMPLE_NETWORK_PROTOCOL
* Snp
,
1274 OUT UINTN
*HdrSize OPTIONAL
,
1275 IN OUT UINTN
*BuffSize
,
1277 OUT EFI_MAC_ADDRESS
*SrcAddr OPTIONAL
,
1278 OUT EFI_MAC_ADDRESS
*DstAddr OPTIONAL
,
1279 OUT UINT16
*Protocol OPTIONAL
1282 LAN9118_DRIVER
*LanDriver
;
1283 UINT32 RxFifoStatus
;
1286 UINT32 PLength
; // Packet length
1291 EFI_MAC_ADDRESS Dst
;
1292 EFI_MAC_ADDRESS Src
;
1293 UINTN DroppedFrames
;
1296 LanDriver
= INSTANCE_FROM_SNP_THIS (Snp
);
1298 #if defined(EVAL_PERFORMANCE)
1299 UINT64 Perf
= GetPerformanceCounterProperties (NULL
, NULL
);
1300 UINT64 StartClock
= GetPerformanceCounter ();
1303 // Check preliminaries
1304 if ((Snp
== NULL
) || (Data
== NULL
) || (BuffSize
== NULL
)) {
1305 return EFI_INVALID_PARAMETER
;
1308 // Check that driver was started and initialised
1309 if (Snp
->Mode
->State
== EfiSimpleNetworkStarted
) {
1310 DEBUG ((EFI_D_WARN
, "Warning: LAN9118 Driver not initialized\n"));
1311 return EFI_DEVICE_ERROR
;
1312 } else if (Snp
->Mode
->State
== EfiSimpleNetworkStopped
) {
1313 DEBUG ((EFI_D_WARN
, "Warning: LAN9118 Driver in stopped state\n"));
1314 return EFI_NOT_STARTED
;
1317 // Count dropped frames
1318 DroppedFrames
= MmioRead32 (LAN9118_RX_DROP
);
1319 LanDriver
->Stats
.RxDroppedFrames
+= DroppedFrames
;
1321 NumPackets
= RxStatusUsedSpace (0, Snp
) / 4;
1323 return EFI_NOT_READY
;
1326 // Read Rx Status (only if not empty)
1327 RxFifoStatus
= MmioRead32 (LAN9118_RX_STATUS
);
1328 LanDriver
->Stats
.RxTotalFrames
+= 1;
1330 // First check for errors
1331 if ((RxFifoStatus
& RXSTATUS_MII_ERROR
) ||
1332 (RxFifoStatus
& RXSTATUS_RXW_TO
) ||
1333 (RxFifoStatus
& RXSTATUS_FTL
) ||
1334 (RxFifoStatus
& RXSTATUS_LCOLL
) ||
1335 (RxFifoStatus
& RXSTATUS_LE
) ||
1336 (RxFifoStatus
& RXSTATUS_DB
))
1338 DEBUG ((EFI_D_WARN
, "Warning: There was an error on frame reception.\n"));
1339 return EFI_DEVICE_ERROR
;
1342 // Check if we got a CRC error
1343 if (RxFifoStatus
& RXSTATUS_CRC_ERROR
) {
1344 DEBUG ((EFI_D_WARN
, "Warning: Crc Error\n"));
1345 LanDriver
->Stats
.RxCrcErrorFrames
+= 1;
1346 LanDriver
->Stats
.RxDroppedFrames
+= 1;
1347 return EFI_DEVICE_ERROR
;
1350 // Check if we got a runt frame
1351 if (RxFifoStatus
& RXSTATUS_RUNT
) {
1352 DEBUG ((EFI_D_WARN
, "Warning: Runt Frame\n"));
1353 LanDriver
->Stats
.RxUndersizeFrames
+= 1;
1354 LanDriver
->Stats
.RxDroppedFrames
+= 1;
1355 return EFI_DEVICE_ERROR
;
1358 // Check filtering status for this packet
1359 if (RxFifoStatus
& RXSTATUS_FILT_FAIL
) {
1360 DEBUG ((EFI_D_WARN
, "Warning: Frame Failed Filtering\n"));
1364 // Check if we got a broadcast frame
1365 if (RxFifoStatus
& RXSTATUS_BCF
) {
1366 LanDriver
->Stats
.RxBroadcastFrames
+= 1;
1369 // Check if we got a multicast frame
1370 if (RxFifoStatus
& RXSTATUS_MCF
) {
1371 LanDriver
->Stats
.RxMulticastFrames
+= 1;
1374 // Check if we got a unicast frame
1375 if ((RxFifoStatus
& RXSTATUS_BCF
) && ((RxFifoStatus
& RXSTATUS_MCF
) == 0)) {
1376 LanDriver
->Stats
.RxUnicastFrames
+= 1;
1379 // Get the received packet length
1380 PLength
= GET_RXSTATUS_PACKET_LENGTH(RxFifoStatus
);
1381 LanDriver
->Stats
.RxTotalBytes
+= (PLength
- 4);
1383 // Check buffer size
1384 if (*BuffSize
< PLength
) {
1385 *BuffSize
= PLength
;
1386 return EFI_BUFFER_TOO_SMALL
;
1389 // If padding is applied, read more DWORDs
1391 Padding
= 4 - (PLength
% 4);
1392 ReadLimit
= (PLength
+ Padding
)/4;
1394 ReadLimit
= PLength
/4;
1398 // Set the amount of data to be transfered out of FIFO for THIS packet
1399 // This can be used to trigger an interrupt, and status can be checked
1400 RxCfgValue
= MmioRead32 (LAN9118_RX_CFG
);
1401 RxCfgValue
&= ~(RXCFG_RX_DMA_CNT_MASK
);
1402 RxCfgValue
|= RXCFG_RX_DMA_CNT (ReadLimit
);
1404 // Set end alignment to 4-bytes
1405 RxCfgValue
&= ~(RXCFG_RX_END_ALIGN_MASK
);
1406 MmioWrite32 (LAN9118_RX_CFG
, RxCfgValue
);
1408 // Update buffer size
1409 *BuffSize
= PLength
; // -4 bytes may be needed: Received in buffer as
1410 // 4 bytes longer than packet actually is, unless
1411 // packet is < 64 bytes
1413 if (HdrSize
!= NULL
)
1414 *HdrSize
= Snp
->Mode
->MediaHeaderSize
;
1416 // Format the pointer
1417 RawData
= (UINT32
*)Data
;
1420 for (Count
= 0; Count
< ReadLimit
; Count
++) {
1421 RawData
[Count
] = MmioRead32 (LAN9118_RX_DATA
);
1424 // Check for Rx errors (worst possible error)
1425 if (MmioRead32 (LAN9118_INT_STS
) & INSTS_RXE
) {
1426 DEBUG ((EFI_D_WARN
, "Warning: Receiver Error. Restarting...\n"));
1428 // Initiate a software reset
1429 Status
= SoftReset (0, Snp
);
1430 if (EFI_ERROR (Status
)) {
1431 DEBUG ((EFI_D_ERROR
, "Error: Soft Reset Failed: Hardware Error.\n"));
1432 return EFI_DEVICE_ERROR
;
1435 // Acknowledge the RXE
1436 MmioWrite32 (LAN9118_INT_STS
, INSTS_RXE
);
1437 gBS
->Stall (LAN9118_STALL
);
1439 // Restart the rx (and do not clear FIFO)
1442 // Say that command could not be sent
1443 return EFI_DEVICE_ERROR
;
1446 // Get the destination address
1447 if (DstAddr
!= NULL
) {
1448 Dst
.Addr
[0] = (RawData
[0] & 0xFF);
1449 Dst
.Addr
[1] = (RawData
[0] & 0xFF00) >> 8;
1450 Dst
.Addr
[2] = (RawData
[0] & 0xFF0000) >> 16;
1451 Dst
.Addr
[3] = (RawData
[0] & 0xFF000000) >> 24;
1452 Dst
.Addr
[4] = (RawData
[1] & 0xFF);
1453 Dst
.Addr
[5] = (RawData
[1] & 0xFF00) >> 8;
1454 CopyMem (DstAddr
, &Dst
, NET_ETHER_ADDR_LEN
);
1457 // Get the source address
1458 if (SrcAddr
!= NULL
) {
1459 Src
.Addr
[0] = (RawData
[1] & 0xFF0000) >> 16;
1460 Src
.Addr
[1] = (RawData
[1] & 0xFF000000) >> 24;
1461 Src
.Addr
[2] = (RawData
[2] & 0xFF);
1462 Src
.Addr
[3] = (RawData
[2] & 0xFF00) >> 8;
1463 Src
.Addr
[4] = (RawData
[2] & 0xFF0000) >> 16;
1464 Src
.Addr
[5] = (RawData
[2] & 0xFF000000) >> 24;
1465 CopyMem (SrcAddr
,&Src
, NET_ETHER_ADDR_LEN
);
1469 if (Protocol
!= NULL
) {
1470 *Protocol
= NTOHS (RawData
[3] & 0xFFFF);
1473 #if defined(EVAL_PERFORMANCE)
1474 UINT64 EndClock
= GetPerformanceCounter ();
1475 DEBUG ((EFI_D_ERROR
, "Receive Time processing: %d counts @ %d Hz\n", StartClock
- EndClock
,Perf
));
1478 LanDriver
->Stats
.RxGoodFrames
+= 1;