X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=blobdiff_plain;f=EmbeddedPkg%2FDrivers%2FLan9118Dxe%2FLan9118Dxe.c;h=e1375bb63ea12517a6d4e6703b279d5586c4a929;hp=fcaa351bf2d31cf08521315848ffc0a364432e73;hb=878b807a435eefbb1d76f9bdec30cb3526521a5e;hpb=46f2c53b544438c735708abba5dc66f83fd2dc4f diff --git a/EmbeddedPkg/Drivers/Lan9118Dxe/Lan9118Dxe.c b/EmbeddedPkg/Drivers/Lan9118Dxe/Lan9118Dxe.c index fcaa351bf2..e1375bb63e 100644 --- a/EmbeddedPkg/Drivers/Lan9118Dxe/Lan9118Dxe.c +++ b/EmbeddedPkg/Drivers/Lan9118Dxe/Lan9118Dxe.c @@ -2,19 +2,12 @@ * * Copyright (c) 2012-2014, ARM Limited. All rights reserved. * -* This program and the accompanying materials -* are licensed and made available under the terms and conditions of the BSD License -* which accompanies this distribution. The full text of the license may be found at -* http://opensource.org/licenses/bsd-license.php -* -* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +* SPDX-License-Identifier: BSD-2-Clause-Patent * **/ #include "Lan9118Dxe.h" - typedef struct { MAC_ADDR_DEVICE_PATH Lan9118; EFI_DEVICE_PATH_PROTOCOL End; @@ -26,14 +19,13 @@ LAN9118_DEVICE_PATH Lan9118PathTemplate = { MESSAGING_DEVICE_PATH, MSG_MAC_ADDR_DP, { (UINT8) (sizeof(MAC_ADDR_DEVICE_PATH)), (UINT8) ((sizeof(MAC_ADDR_DEVICE_PATH)) >> 8) } }, - { 0 }, + { { 0 } }, 0 }, { END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, - sizeof(EFI_DEVICE_PATH_PROTOCOL), - 0 + { sizeof(EFI_DEVICE_PATH_PROTOCOL), 0 } } }; @@ -100,16 +92,25 @@ Lan9118DxeEntry ( SnpMode->NvRamSize = 0; // No NVRAM with this device SnpMode->NvRamAccessSize = 0; // No NVRAM with this device - // Update network mode information - SnpMode->ReceiveFilterMask = EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST | - EFI_SIMPLE_NETWORK_RECEIVE_UNICAST | - EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST | - EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS;/* | - EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST;*/ - // Current allowed settings - SnpMode->ReceiveFilterSetting = EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST | - EFI_SIMPLE_NETWORK_RECEIVE_UNICAST | - EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST; + // + // Claim that all receive filter settings are supported, though the MULTICAST mode + // is not completely supported. The LAN9118 Ethernet controller is only able to + // do a "hash filtering" and not a perfect filtering on multicast addresses. The + // controller does not filter the multicast addresses directly but a hash value + // of them. The hash value of a multicast address is derived from its CRC and + // ranges from 0 to 63 included. + // We claim that the perfect MULTICAST filtering mode is supported because + // we do not want the user to switch directly to the PROMISCOUS_MULTICAST mode + // and thus not being able to take advantage of the hash filtering. + // + SnpMode->ReceiveFilterMask = EFI_SIMPLE_NETWORK_RECEIVE_UNICAST | + EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST | + EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST | + EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS | + EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST; + + // We do not intend to receive anything for the time being. + SnpMode->ReceiveFilterSetting = 0; // LAN9118 has 64bit hash table, can filter 64 MCast MAC Addresses SnpMode->MaxMCastFilterCount = MAX_MCAST_FILTER_CNT; @@ -135,7 +136,7 @@ Lan9118DxeEntry ( // Power up the device so we can find the MAC address Status = Lan9118Initialize (Snp); if (EFI_ERROR (Status)) { - DEBUG ((EFI_D_ERROR, "Lan9118: Error initialising hardware\n")); + DEBUG ((EFI_D_ERROR, "LAN9118: Error initialising hardware\n")); return EFI_DEVICE_ERROR; } @@ -176,7 +177,7 @@ Lan9118DxeEntry ( EFI_STATUS EFIAPI SnpStart ( - IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp + IN EFI_SIMPLE_NETWORK_PROTOCOL *Snp ) { // Check Snp instance @@ -185,10 +186,9 @@ SnpStart ( } // Check state - if ((Snp->Mode->State == EfiSimpleNetworkStarted) || (Snp->Mode->State == EfiSimpleNetworkInitialized)) { + if ((Snp->Mode->State == EfiSimpleNetworkStarted) || + (Snp->Mode->State == EfiSimpleNetworkInitialized) ) { return EFI_ALREADY_STARTED; - } else if (Snp->Mode->State == EfiSimpleNetworkMaxState) { - return EFI_DEVICE_ERROR; } // Change state @@ -212,7 +212,7 @@ SnpStop ( } // Check state of the driver - if ((Snp->Mode->State == EfiSimpleNetworkStopped) || (Snp->Mode->State == EfiSimpleNetworkMaxState)) { + if (Snp->Mode->State == EfiSimpleNetworkStopped) { return EFI_NOT_STARTED; } @@ -276,7 +276,8 @@ SnpInitialize ( } // Initiate a PHY reset - if (PhySoftReset (PHY_RESET_PMT | PHY_RESET_CHECK_LINK, Snp) < 0) { + Status = PhySoftReset (PHY_RESET_PMT, Snp); + if (EFI_ERROR (Status)) { Snp->Mode->State = EfiSimpleNetworkStopped; DEBUG ((EFI_D_WARN, "Warning: Link not ready after TimeOut. Check ethernet cable\n")); return EFI_NOT_STARTED; @@ -290,7 +291,7 @@ SnpInitialize ( } // Read the PM register - PmConf = MmioRead32 (LAN9118_PMT_CTRL); + PmConf = Lan9118MmioRead32 (LAN9118_PMT_CTRL); // MPTCTRL_WOL_EN: Allow Wake-On-Lan to detect wake up frames or magic packets // MPTCTRL_ED_EN: Allow energy detection to allow lowest power consumption mode @@ -299,9 +300,7 @@ SnpInitialize ( PmConf |= (MPTCTRL_WOL_EN | MPTCTRL_ED_EN | MPTCTRL_PME_EN); // Write the current configuration to the register - MmioWrite32 (LAN9118_PMT_CTRL, PmConf); - gBS->Stall (LAN9118_STALL); - gBS->Stall (LAN9118_STALL); + Lan9118MmioWrite32 (LAN9118_PMT_CTRL, PmConf); // Configure GPIO and HW Status = ConfigureHardware (HW_CONF_USE_LEDS, Snp); @@ -336,7 +335,7 @@ SnpInitialize ( // Do auto-negotiation if supported Status = AutoNegotiate (AUTO_NEGOTIATE_ADVERTISE_ALL, Snp); if (EFI_ERROR(Status)) { - DEBUG ((EFI_D_WARN, "Lan9118: Auto Negociation not supported.\n")); + DEBUG ((EFI_D_WARN, "LAN9118: Auto Negotiation failed.\n")); } // Configure flow control depending on speed capabilities @@ -345,19 +344,14 @@ SnpInitialize ( return Status; } - // Enable the receiver and transmitter - Status = StartRx (0, Snp); - if (EFI_ERROR(Status)) { - return Status; - } - + // Enable the transmitter Status = StartTx (START_TX_MAC | START_TX_CFG, Snp); if (EFI_ERROR(Status)) { return Status; } // Now acknowledge all interrupts - MmioWrite32 (LAN9118_INT_STS, ~0); + Lan9118MmioWrite32 (LAN9118_INT_STS, ~0); // Declare the driver as initialized Snp->Mode->State = EfiSimpleNetworkInitialized; @@ -376,9 +370,10 @@ SnpReset ( IN BOOLEAN Verification ) { - UINT32 PmConf; - UINT32 HwConf; - UINT32 ResetFlags; + UINT32 PmConf; + UINT32 HwConf; + UINT32 ResetFlags; + EFI_STATUS Status; PmConf = 0; HwConf = 0; @@ -399,7 +394,8 @@ SnpReset ( } // Initiate a PHY reset - if (PhySoftReset (PHY_RESET_PMT | PHY_RESET_CHECK_LINK, Snp) < 0) { + Status = PhySoftReset (PHY_RESET_PMT, Snp); + if (EFI_ERROR (Status)) { Snp->Mode->State = EfiSimpleNetworkStopped; return EFI_NOT_STARTED; } @@ -411,13 +407,14 @@ SnpReset ( ResetFlags |= SOFT_RESET_SELF_TEST; } - if (SoftReset (ResetFlags, Snp) < 0) { + Status = SoftReset (ResetFlags, Snp); + if (EFI_ERROR (Status)) { DEBUG ((EFI_D_WARN, "Warning: Soft Reset Failed: Hardware Error\n")); return EFI_DEVICE_ERROR; } // Read the PM register - PmConf = MmioRead32 (LAN9118_PMT_CTRL); + PmConf = Lan9118MmioRead32 (LAN9118_PMT_CTRL); // MPTCTRL_WOL_EN: Allow Wake-On-Lan to detect wake up frames or magic packets // MPTCTRL_ED_EN: Allow energy detection to allow lowest power consumption mode @@ -425,17 +422,21 @@ SnpReset ( PmConf |= (MPTCTRL_WOL_EN | MPTCTRL_ED_EN | MPTCTRL_PME_EN); // Write the current configuration to the register - MmioWrite32 (LAN9118_PMT_CTRL, PmConf); - gBS->Stall (LAN9118_STALL); + Lan9118MmioWrite32 (LAN9118_PMT_CTRL, PmConf); + + // Reactivate the LEDs + Status = ConfigureHardware (HW_CONF_USE_LEDS, Snp); + if (EFI_ERROR (Status)) { + return Status; + } // Check that a buffer size was specified in SnpInitialize if (gTxBuffer != 0) { - HwConf = MmioRead32 (LAN9118_HW_CFG); // Read the HW register + HwConf = Lan9118MmioRead32 (LAN9118_HW_CFG); // Read the HW register HwConf &= ~HW_CFG_TX_FIFO_SIZE_MASK; // Clear buffer bits first HwConf |= HW_CFG_TX_FIFO_SIZE(gTxBuffer); // assign size chosen in SnpInitialize - MmioWrite32 (LAN9118_HW_CFG, HwConf); // Write the conf - gBS->Stall (LAN9118_STALL); + Lan9118MmioWrite32 (LAN9118_HW_CFG, HwConf); // Write the conf } // Enable the receiver and transmitter and clear their contents @@ -443,7 +444,7 @@ SnpReset ( StartTx (START_TX_MAC | START_TX_CFG | START_TX_CLEAR, Snp); // Now acknowledge all interrupts - MmioWrite32 (LAN9118_INT_STS, ~0); + Lan9118MmioWrite32 (LAN9118_INT_STS, ~0); return EFI_SUCCESS; } @@ -458,6 +459,8 @@ SnpShutdown ( IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp ) { + EFI_STATUS Status; + // Check Snp Instance if (Snp == NULL) { return EFI_INVALID_PARAMETER; @@ -468,180 +471,267 @@ SnpShutdown ( DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver not yet initialized\n")); return EFI_DEVICE_ERROR; } else if (Snp->Mode->State == EfiSimpleNetworkStopped) { - DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver in stopped state\n")); + DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver not started\n")); return EFI_NOT_STARTED; } // Initiate a PHY reset - PhySoftReset (PHY_RESET_PMT, Snp); + Status = PhySoftReset (PHY_RESET_PMT, Snp); + if (EFI_ERROR (Status)) { + return Status; + } // Initiate a software reset - if (SoftReset (0, Snp) < 0) { + Status = SoftReset (0, Snp); + if (EFI_ERROR (Status)) { DEBUG ((EFI_D_WARN, "Warning: Soft Reset Failed: Hardware Error\n")); - return EFI_DEVICE_ERROR; + return Status; } + // Back to the started and thus not initialized state + Snp->Mode->State = EfiSimpleNetworkStarted; + return EFI_SUCCESS; } +/** + Enable and/or disable the receive filters of the LAN9118 + + Please refer to the UEFI specification for the precedence rules among the + Enable, Disable and ResetMCastFilter parameters. + + @param[in] Snp A pointer to the EFI_SIMPLE_NETWORK_PROTOCOL + instance. + @param[in] Enable A bit mask of receive filters to enable. + @param[in] Disable A bit mask of receive filters to disable. + @param[in] ResetMCastFilter Set to TRUE to reset the contents of the multicast + receive filters on the network interface to + their default values. + @param[in] MCastFilterCnt Number of multicast HW MAC addresses in the new + MCastFilter list. This value must be less than or + equal to the MCastFilterCnt field of + EFI_SIMPLE_NETWORK_MODE. This field is optional if + ResetMCastFilter is TRUE. + @param[in] MCastFilter A pointer to a list of new multicast receive + filter HW MAC addresses. This list will replace + any existing multicast HW MAC address list. This + field is optional if ResetMCastFilter is TRUE. + + @retval EFI_SUCCESS The receive filters of the LAN9118 were updated. + @retval EFI_NOT_STARTED The LAN9118 has not been started. + @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE : + . This is NULL + . Multicast is being enabled (the + EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST bit is set in + Enable, it is not set in Disable, and ResetMCastFilter + is FALSE) and MCastFilterCount is zero. + . Multicast is being enabled and MCastFilterCount is + greater than Snp->Mode->MaxMCastFilterCount. + . Multicast is being enabled and MCastFilter is NULL + . Multicast is being enabled and one or more of the + addresses in the MCastFilter list are not valid + multicast MAC addresses. + @retval EFI_DEVICE_ERROR The LAN9118 has been started but not initialized. -/* - * UEFI ReceiveFilters() function - * - */ +**/ EFI_STATUS EFIAPI SnpReceiveFilters ( - IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp, - IN UINT32 Enable, - IN UINT32 Disable, - IN BOOLEAN Reset, - IN UINTN NumMfilter OPTIONAL, - IN EFI_MAC_ADDRESS *Mfilter OPTIONAL + IN EFI_SIMPLE_NETWORK_PROTOCOL *Snp, + IN UINT32 Enable, + IN UINT32 Disable, + IN BOOLEAN ResetMCastFilter, + IN UINTN MCastFilterCnt OPTIONAL, + IN EFI_MAC_ADDRESS *MCastFilter OPTIONAL ) { - UINT32 MacCSRValue; - UINT32 MultHashTableHigh; - UINT32 MultHashTableLow; - UINT32 Crc; - UINT8 BitToSelect; - UINT32 Count; + EFI_SIMPLE_NETWORK_MODE *Mode; + UINT32 MultHashTableHigh; + UINT32 MultHashTableLow; + UINT32 Count; + UINT32 Crc; + UINT8 HashValue; + UINT32 MacCSRValue; + UINT32 ReceiveFilterSetting; + EFI_MAC_ADDRESS *Mac; + EFI_MAC_ADDRESS ZeroMac; - MacCSRValue = 0; - MultHashTableHigh = 0; - MultHashTableLow = 0; - Crc = 0xFFFFFFFF; - BitToSelect = 0; - Count = 0; + // Check Snp Instance + if (Snp == NULL) { + return EFI_INVALID_PARAMETER; + } + Mode = Snp->Mode; // Check that driver was started and initialised - if (Snp->Mode->State == EfiSimpleNetworkStarted) { + if (Mode->State == EfiSimpleNetworkStarted) { DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver not initialized\n")); return EFI_DEVICE_ERROR; - } else if (Snp->Mode->State == EfiSimpleNetworkStopped) { + } else if (Mode->State == EfiSimpleNetworkStopped) { DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver in stopped state\n")); return EFI_NOT_STARTED; } - // If reset then clear the filter registers - if (Reset) { - Enable |= EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST; - IndirectMACWrite32 (INDIRECT_MAC_INDEX_HASHL, 0x00000000); - IndirectMACWrite32 (INDIRECT_MAC_INDEX_HASHH, 0x00000000); + if ((Enable & (~Mode->ReceiveFilterMask)) || + (Disable & (~Mode->ReceiveFilterMask)) ) { + return EFI_INVALID_PARAMETER; } - // Set the hash tables - if ((NumMfilter > 0) && (!Reset)) { - - // Read the Multicast High Hash Table - MultHashTableHigh = IndirectMACRead32 (INDIRECT_MAC_INDEX_HASHH); + // + // Check the validity of the multicast setting and compute the + // hash values of the multicast mac addresses to listen to. + // - // Read the Multicast Low Hash Table - MultHashTableLow = IndirectMACRead32 (INDIRECT_MAC_INDEX_HASHL); + MultHashTableHigh = 0; + MultHashTableLow = 0; + if ((!ResetMCastFilter) && + ((Disable & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST) == 0) && + ((Enable & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST) != 0) ) { + if ((MCastFilterCnt == 0) || + (MCastFilterCnt > Mode->MaxMCastFilterCount) || + (MCastFilter == NULL) ) { + return EFI_INVALID_PARAMETER; + } + // + // Check the validity of all multicast addresses before to change + // anything. + // + for (Count = 0; Count < MCastFilterCnt; Count++) { + if ((MCastFilter[Count].Addr[0] & 1) == 0) { + return EFI_INVALID_PARAMETER; + } + } + // // Go through each filter address and set appropriate bits on hash table - for (Count = 0; Count < NumMfilter; Count++) { + // + for (Count = 0; Count < MCastFilterCnt; Count++) { + Mac = &(MCastFilter[Count]); + CopyMem (&Mode->MCastFilter[Count], Mac, sizeof(EFI_MAC_ADDRESS)); - // Generate a 32-bit CRC for Ethernet - Crc = GenEtherCrc32 (&Mfilter[Count],6); + Crc = GenEtherCrc32 (Mac, NET_ETHER_ADDR_LEN); //gBS->CalculateCrc32 ((VOID*)&Mfilter[Count],6,&Crc); <-- doesn't work as desired - // Get the most significant 6 bits to index hash registers - BitToSelect = (Crc >> 26) & 0x3F; + // + // The most significant 6 bits of the MAC address CRC constitute the hash + // value of the MAC address. + // + HashValue = (Crc >> 26) & 0x3F; // Select hashlow register if MSB is not set - if ((BitToSelect & 0x20) == 0) { - MultHashTableLow |= (1 << BitToSelect); + if ((HashValue & 0x20) == 0) { + MultHashTableLow |= (1 << HashValue); } else { - MultHashTableHigh |= (1 << (BitToSelect & 0x1F)); + MultHashTableHigh |= (1 << (HashValue & 0x1F)); } } - - // Write the desired hash - IndirectMACWrite32 (INDIRECT_MAC_INDEX_HASHL, MultHashTableLow); - IndirectMACWrite32 (INDIRECT_MAC_INDEX_HASHH, MultHashTableHigh); + Mode->MCastFilterCount = MCastFilterCnt; + } else if (ResetMCastFilter) { + Mode->MCastFilterCount = 0; + } else { + MultHashTableLow = IndirectMACRead32 (INDIRECT_MAC_INDEX_HASHL); + MultHashTableHigh = IndirectMACRead32 (INDIRECT_MAC_INDEX_HASHH); } + // + // Before to change anything, stop and reset the reception of + // packets. + // + StopRx (STOP_RX_CLEAR, Snp); + + // + // Write the mask of the selected hash values for the multicast filtering. + // The two masks are set to zero if the multicast filtering is not enabled. + // + IndirectMACWrite32 (INDIRECT_MAC_INDEX_HASHL, MultHashTableLow); + IndirectMACWrite32 (INDIRECT_MAC_INDEX_HASHH, MultHashTableHigh); + + ReceiveFilterSetting = (Mode->ReceiveFilterSetting | Enable) & (~Disable); + + // // Read MAC controller - MacCSRValue = IndirectMACRead32 (INDIRECT_MAC_INDEX_CR); + // + MacCSRValue = IndirectMACRead32 (INDIRECT_MAC_INDEX_CR); + MacCSRValue &= ~(MACCR_HPFILT | MACCR_BCAST | MACCR_PRMS | MACCR_MCPAS); - // Set the options for the MAC_CSR - if (Enable & EFI_SIMPLE_NETWORK_RECEIVE_UNICAST) { - StartRx (0, Snp); + if (ReceiveFilterSetting & EFI_SIMPLE_NETWORK_RECEIVE_UNICAST) { + Lan9118SetMacAddress (&Mode->CurrentAddress, Snp); DEBUG ((DEBUG_NET, "Allowing Unicast Frame Reception\n")); + } else { + // + // The Unicast packets do not have to be listen to, set the MAC + // address of the LAN9118 to be the "not configured" all zeroes + // ethernet MAC address. + // + ZeroMem (&ZeroMac, NET_ETHER_ADDR_LEN); + Lan9118SetMacAddress (&ZeroMac, Snp); } - if (Disable & EFI_SIMPLE_NETWORK_RECEIVE_UNICAST) { - StopRx (0, Snp); - DEBUG ((DEBUG_NET, "Disabling Unicast Frame Reception\n")); - } - - if (Enable & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST) { + if (ReceiveFilterSetting & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST) { MacCSRValue |= MACCR_HPFILT; DEBUG ((DEBUG_NET, "Allowing Multicast Frame Reception\n")); } - if (Disable & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST) { - MacCSRValue &= ~MACCR_HPFILT; - DEBUG ((DEBUG_NET, "Disabling Multicast Frame Reception\n")); - } - - if (Enable & EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST) { - MacCSRValue &= ~(MACCR_BCAST); - DEBUG ((DEBUG_NET, "Allowing Broadcast Frame Reception\n")); + if (ReceiveFilterSetting & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST) { + MacCSRValue |= MACCR_MCPAS; + DEBUG ((DEBUG_NET, "Enabling Promiscuous Multicast Mode\n")); } - if (Disable & EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST) { + if ((ReceiveFilterSetting & EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST) == 0) { MacCSRValue |= MACCR_BCAST; - DEBUG ((DEBUG_NET, "Disabling Broadcast Frame Reception\n")); + } else { + DEBUG ((DEBUG_NET, "Allowing Broadcast Frame Reception\n")); } - if (Enable & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS) { + if (ReceiveFilterSetting & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS) { MacCSRValue |= MACCR_PRMS; DEBUG ((DEBUG_NET, "Enabling Promiscuous Mode\n")); } - if (Disable & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS) { - MacCSRValue &= ~MACCR_PRMS; - DEBUG ((DEBUG_NET, "Disabling Promiscuous Mode\n")); - } - - if (Enable & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST) { - MacCSRValue |= (MACCR_HPFILT | MACCR_PRMS); - DEBUG ((DEBUG_NET, "Enabling Promiscuous Multicast Mode\n")); - } - - if (Disable & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST) { - MacCSRValue &= ~(MACCR_HPFILT | MACCR_PRMS); - DEBUG ((DEBUG_NET, "Disabling Promiscuous Multicast Mode\n")); - } - + // // Write the options to the MAC_CSR + // IndirectMACWrite32 (INDIRECT_MAC_INDEX_CR, MacCSRValue); - gBS->Stall (LAN9118_STALL); + + // + // If we have to retrieve something, start packet reception. + // + Mode->ReceiveFilterSetting = ReceiveFilterSetting; + if (ReceiveFilterSetting != 0) { + StartRx (0, Snp); + } return EFI_SUCCESS; } -/* - * UEFI StationAddress() function - * - */ +/** + Modify of reset the current station address + + @param[in] Snp A pointer to the EFI_SIMPLE_NETWORK_PROTOCOL + instance. + @param[in] Reset Flag used to reset the station address to the + LAN9118's permanent address. + @param[in] New New station address to be used for the network interface. + + @retval EFI_SUCCESS The LAN9118's station address was updated. + @retval EFI_NOT_STARTED The LAN9118 has not been started. + @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE : + . The "New" station address is invalid. + . "Reset" is FALSE and "New" is NULL. + @retval EFI_DEVICE_ERROR The LAN9118 has been started but not initialized. + +**/ EFI_STATUS EFIAPI SnpStationAddress ( - IN EFI_SIMPLE_NETWORK_PROTOCOL *Snp, - IN BOOLEAN Reset, - IN EFI_MAC_ADDRESS *NewMac + IN EFI_SIMPLE_NETWORK_PROTOCOL *Snp, + IN BOOLEAN Reset, + IN EFI_MAC_ADDRESS *New ) { - DEBUG ((DEBUG_NET, "SnpStationAddress()\n")); - UINT32 Count; - UINT8 PermAddr[6]; - UINT64 DefaultMacAddress; + UINT8 PermAddr[NET_ETHER_ADDR_LEN]; - Count = 0; + DEBUG ((DEBUG_NET, "SnpStationAddress()\n")); // Check Snp instance if (Snp == NULL) { @@ -661,25 +751,41 @@ SnpStationAddress ( if (Reset) { // Try using EEPROM first. Read the first byte of data from EEPROM at the address 0x0 if ((IndirectEEPROMRead32 (0) & 0xFF) == EEPROM_EXTERNAL_SERIAL_EEPROM) { - for (Count = 1; Count < 7; Count++) { - PermAddr[Count - 1] = IndirectEEPROMRead32 (Count); + for (Count = 0; Count < NET_ETHER_ADDR_LEN; Count++) { + PermAddr[Count] = IndirectEEPROMRead32 (Count + 1); } - - // Write address + New = (EFI_MAC_ADDRESS *) PermAddr; Lan9118SetMacAddress ((EFI_MAC_ADDRESS *) PermAddr, Snp); } else { - DEBUG ((EFI_D_ERROR, "Lan9118: Warning: No valid MAC address in EEPROM, using fallback\n")); - DefaultMacAddress = FixedPcdGet64 (PcdLan9118DefaultMacAddress); - Lan9118SetMacAddress ((EFI_MAC_ADDRESS *) &DefaultMacAddress, Snp); + DEBUG ((EFI_D_ERROR, "LAN9118: Warning: No valid MAC address in EEPROM, using fallback\n")); + New = (EFI_MAC_ADDRESS*) (FixedPcdGet64 (PcdLan9118DefaultMacAddress)); } } else { // Otherwise use the specified new MAC address - if (NewMac == NULL) { + if (New == NULL) { return EFI_INVALID_PARAMETER; } + // + // If it is a multicast address, it is not valid. + // + if (New->Addr[0] & 0x01) { + return EFI_INVALID_PARAMETER; + } + } - // Write address - Lan9118SetMacAddress (NewMac, Snp); + CopyMem (&Snp->Mode->CurrentAddress, New, NET_ETHER_ADDR_LEN); + + // + // If packet reception is currently activated, stop and reset it, + // set the new ethernet address and restart the packet reception. + // Otherwise, nothing to do, the MAC address will be updated in + // SnpReceiveFilters() when the UNICAST packet reception will be + // activated. + // + if (Snp->Mode->ReceiveFilterSetting != 0) { + StopRx (STOP_RX_CLEAR, Snp); + Lan9118SetMacAddress (New, Snp); + StartRx (0, Snp); } return EFI_SUCCESS; @@ -698,7 +804,8 @@ SnpStatistics ( OUT EFI_NETWORK_STATISTICS *Statistics ) { - LAN9118_DRIVER *LanDriver; + LAN9118_DRIVER *LanDriver; + EFI_STATUS Status; LanDriver = INSTANCE_FROM_SNP_THIS (Snp); @@ -718,31 +825,39 @@ SnpStatistics ( return EFI_NOT_STARTED; } - // Check pointless condition - if ((!Reset) && (StatSize == NULL) && (Statistics == NULL)) { - return EFI_SUCCESS; - } - - // Check the parameters - if ((StatSize == NULL) && (Statistics != NULL)) { - return EFI_INVALID_PARAMETER; - } - - // Do a reset if required + // + // Do a reset if required. It is not clearly stated in the UEFI specification + // whether the reset has to be done before to copy the statistics in "Statictics" + // or after. It is a bit strange to do it before but that is what is expected by + // the SCT test on Statistics() with reset : "0x3de76704,0x4bf5,0x42cd,0x8c,0x89, + // 0x54,0x7e,0x4f,0xad,0x4f,0x24". + // if (Reset) { ZeroMem (&LanDriver->Stats, sizeof(EFI_NETWORK_STATISTICS)); } - // Check buffer size - if (*StatSize < sizeof(EFI_NETWORK_STATISTICS)) { - *StatSize = sizeof(EFI_NETWORK_STATISTICS); - return EFI_BUFFER_TOO_SMALL; + Status = EFI_SUCCESS; + if (StatSize == NULL) { + if (Statistics != NULL) { + return EFI_INVALID_PARAMETER; + } + } else { + if (Statistics == NULL) { + Status = EFI_BUFFER_TOO_SMALL; + } else { + // Fill in the statistics + CopyMem ( + Statistics, &LanDriver->Stats, + MIN (*StatSize, sizeof (EFI_NETWORK_STATISTICS)) + ); + if (*StatSize < sizeof (EFI_NETWORK_STATISTICS)) { + Status = EFI_BUFFER_TOO_SMALL; + } + } + *StatSize = sizeof (EFI_NETWORK_STATISTICS); } - // Fill in the statistics - CopyMem(&Statistics, &LanDriver->Stats, sizeof(EFI_NETWORK_STATISTICS)); - - return EFI_SUCCESS; + return Status; } /* @@ -837,9 +952,9 @@ SnpNvData ( EFI_STATUS EFIAPI SnpGetStatus ( - IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp, - OUT UINT32 *IrqStat OPTIONAL, - OUT VOID **TxBuff OPTIONAL + IN EFI_SIMPLE_NETWORK_PROTOCOL *Snp, + OUT UINT32 *IrqStat OPTIONAL, + OUT VOID **TxBuff OPTIONAL ) { UINT32 FifoInt; @@ -857,7 +972,12 @@ SnpGetStatus ( return EFI_INVALID_PARAMETER; } - if (Snp->Mode->State != EfiSimpleNetworkInitialized) { + // Check that driver was started and initialised + if (Snp->Mode->State == EfiSimpleNetworkStarted) { + DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver not initialized\n")); + return EFI_DEVICE_ERROR; + } else if (Snp->Mode->State == EfiSimpleNetworkStopped) { + DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver in stopped state\n")); return EFI_NOT_STARTED; } @@ -865,51 +985,46 @@ SnpGetStatus ( // consumer of SNP does not call GetStatus.) // TODO will we lose TxStatuses if this happens? Maybe in SnpTransmit we // should check for it and dump the TX Status FIFO. - FifoInt = MmioRead32 (LAN9118_FIFO_INT); + FifoInt = Lan9118MmioRead32 (LAN9118_FIFO_INT); // Clear the TX Status FIFO Overflow if ((FifoInt & INSTS_TXSO) == 0) { FifoInt |= INSTS_TXSO; - MmioWrite32 (LAN9118_FIFO_INT, FifoInt); + Lan9118MmioWrite32 (LAN9118_FIFO_INT, FifoInt); } // Read interrupt status if IrqStat is not NULL if (IrqStat != NULL) { + *IrqStat = 0; // Check for receive interrupt - if (MmioRead32 (LAN9118_INT_STS) & INSTS_RSFL) { // Data moved from rx FIFO + if (Lan9118MmioRead32 (LAN9118_INT_STS) & INSTS_RSFL) { // Data moved from rx FIFO *IrqStat |= EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT; - MmioWrite32 (LAN9118_INT_STS,INSTS_RSFL); - } else { - *IrqStat &= ~EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT; + Lan9118MmioWrite32 (LAN9118_INT_STS,INSTS_RSFL); } // Check for transmit interrupt - if (MmioRead32 (LAN9118_INT_STS) & INSTS_TSFL) { + if (Lan9118MmioRead32 (LAN9118_INT_STS) & INSTS_TSFL) { *IrqStat |= EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT; - MmioWrite32 (LAN9118_INT_STS,INSTS_TSFL); - } else { - *IrqStat &= ~EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT; + Lan9118MmioWrite32 (LAN9118_INT_STS,INSTS_TSFL); } // Check for software interrupt - if (MmioRead32 (LAN9118_INT_STS) & INSTS_SW_INT) { + if (Lan9118MmioRead32 (LAN9118_INT_STS) & INSTS_SW_INT) { *IrqStat |= EFI_SIMPLE_NETWORK_SOFTWARE_INTERRUPT; - MmioWrite32 (LAN9118_INT_STS,INSTS_SW_INT); - } else { - *IrqStat &= ~EFI_SIMPLE_NETWORK_SOFTWARE_INTERRUPT; + Lan9118MmioWrite32 (LAN9118_INT_STS,INSTS_SW_INT); } } // Check Status of transmitted packets // (We ignore TXSTATUS_NO_CA has it might happen in Full Duplex) - NumTxStatusEntries = MmioRead32(LAN9118_TX_FIFO_INF) & TXFIFOINF_TXSUSED_MASK; + NumTxStatusEntries = Lan9118MmioRead32(LAN9118_TX_FIFO_INF) & TXFIFOINF_TXSUSED_MASK; if (NumTxStatusEntries > 0) { - TxStatus = MmioRead32 (LAN9118_TX_STATUS); + TxStatus = Lan9118MmioRead32 (LAN9118_TX_STATUS); PacketTag = TxStatus >> 16; TxStatus = TxStatus & 0xFFFF; - if ((TxStatus & TXSTATUS_ES) && TxStatus != (TXSTATUS_ES | TXSTATUS_NO_CA)) { + if ((TxStatus & TXSTATUS_ES) && (TxStatus != (TXSTATUS_ES | TXSTATUS_NO_CA))) { DEBUG ((EFI_D_ERROR, "LAN9118: There was an error transmitting. TxStatus=0x%08x:", TxStatus)); if (TxStatus & TXSTATUS_NO_CA) { DEBUG ((EFI_D_ERROR, "- No carrier\n")); @@ -930,29 +1045,41 @@ SnpGetStatus ( DEBUG ((EFI_D_ERROR, "- Lost carrier during Tx\n")); } return EFI_DEVICE_ERROR; - } else { + } else if (TxBuff != NULL) { LanDriver->Stats.TxTotalFrames += 1; *TxBuff = LanDriver->TxRing[PacketTag % LAN9118_TX_RING_NUM_ENTRIES]; } + } else if (TxBuff != NULL) { + *TxBuff = NULL; } // Check for a TX Error interrupt - Interrupts = MmioRead32 (LAN9118_INT_STS); + Interrupts = Lan9118MmioRead32 (LAN9118_INT_STS); if (Interrupts & INSTS_TXE) { DEBUG ((EFI_D_ERROR, "LAN9118: Transmitter error. Restarting...")); - // Initiate a software reset - if (SoftReset (0, Snp) < 0) { + // Software reset, the TXE interrupt is cleared by the reset. + Status = SoftReset (0, Snp); + if (EFI_ERROR (Status)) { DEBUG ((EFI_D_ERROR, "\n\tSoft Reset Failed: Hardware Error\n")); return EFI_DEVICE_ERROR; } - // Acknowledge the TXE - MmioWrite32 (LAN9118_INT_STS, INSTS_TXE); - gBS->Stall (LAN9118_STALL); + // Reactivate the LEDs + Status = ConfigureHardware (HW_CONF_USE_LEDS, Snp); + if (EFI_ERROR (Status)) { + return Status; + } - // Restart the transmitter + // + // Restart the transmitter and if necessary the receiver. + // Do not ask for FIFO reset as it has already been done + // by SoftReset(). + // StartTx (START_TX_MAC | START_TX_CFG, Snp); + if (Snp->Mode->ReceiveFilterSetting != 0) { + StartRx (0, Snp); + } } // Update the media status @@ -1008,7 +1135,13 @@ SnpTransmit ( if ((Snp == NULL) || (Data == NULL)) { return EFI_INVALID_PARAMETER; } - if (Snp->Mode->State != EfiSimpleNetworkInitialized) { + + // Check that driver was started and initialised + if (Snp->Mode->State == EfiSimpleNetworkStarted) { + DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver not initialized\n")); + return EFI_DEVICE_ERROR; + } else if (Snp->Mode->State == EfiSimpleNetworkStopped) { + DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver in stopped state\n")); return EFI_NOT_STARTED; } @@ -1023,6 +1156,13 @@ SnpTransmit ( } } + // + // Check validity of BufferSize + // + if (BuffSize < Snp->Mode->MediaHeaderSize) { + return EFI_BUFFER_TOO_SMALL; + } + // Before transmitting check the link status /*if (CheckLinkStatus (0, Snp) < 0) { return EFI_NOT_READY; @@ -1072,25 +1212,25 @@ SnpTransmit ( CommandB = TX_CMD_B_PACKET_TAG (PacketTag) | TX_CMD_B_PACKET_LENGTH (BuffSize); // Write the commands first - MmioWrite32 (LAN9118_TX_DATA, CommandA); - MmioWrite32 (LAN9118_TX_DATA, CommandB); + Lan9118MmioWrite32 (LAN9118_TX_DATA, CommandA); + Lan9118MmioWrite32 (LAN9118_TX_DATA, CommandB); // Write the destination address - MmioWrite32 (LAN9118_TX_DATA, + Lan9118MmioWrite32 (LAN9118_TX_DATA, (DstAddr->Addr[0]) | (DstAddr->Addr[1] << 8) | (DstAddr->Addr[2] << 16) | (DstAddr->Addr[3] << 24) ); - MmioWrite32 (LAN9118_TX_DATA, + Lan9118MmioWrite32 (LAN9118_TX_DATA, (DstAddr->Addr[4]) | (DstAddr->Addr[5] << 8) | (SrcAddr->Addr[0] << 16) | // Write the Source Address (SrcAddr->Addr[1] << 24) ); - MmioWrite32 (LAN9118_TX_DATA, + Lan9118MmioWrite32 (LAN9118_TX_DATA, (SrcAddr->Addr[2]) | (SrcAddr->Addr[3] << 8) | (SrcAddr->Addr[4] << 16) | @@ -1098,18 +1238,18 @@ SnpTransmit ( ); // Write the Protocol - MmioWrite32 (LAN9118_TX_DATA, (UINT32)(HTONS (LocalProtocol))); + Lan9118MmioWrite32 (LAN9118_TX_DATA, (UINT32)(HTONS (LocalProtocol))); // Next buffer is the payload 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 // Write the commands - MmioWrite32 (LAN9118_TX_DATA, CommandA); - MmioWrite32 (LAN9118_TX_DATA, CommandB); + Lan9118MmioWrite32 (LAN9118_TX_DATA, CommandA); + Lan9118MmioWrite32 (LAN9118_TX_DATA, CommandB); // Write the payload for (Count = 0; Count < ((BuffSize + 3) >> 2) - 3; Count++) { - MmioWrite32 (LAN9118_TX_DATA, LocalData[Count + 3]); + Lan9118MmioWrite32 (LAN9118_TX_DATA, LocalData[Count + 3]); } } else { // Format pointer @@ -1120,12 +1260,12 @@ SnpTransmit ( CommandB = TX_CMD_B_PACKET_TAG (PacketTag) | TX_CMD_B_PACKET_LENGTH (BuffSize); // Write the commands first - MmioWrite32 (LAN9118_TX_DATA, CommandA); - MmioWrite32 (LAN9118_TX_DATA, CommandB); + Lan9118MmioWrite32 (LAN9118_TX_DATA, CommandA); + Lan9118MmioWrite32 (LAN9118_TX_DATA, CommandB); // Write all the data for (Count = 0; Count < ((BuffSize + 3) >> 2); Count++) { - MmioWrite32 (LAN9118_TX_DATA, LocalData[Count]); + Lan9118MmioWrite32 (LAN9118_TX_DATA, LocalData[Count]); } } @@ -1161,18 +1301,20 @@ SnpReceive ( OUT UINT16 *Protocol OPTIONAL ) { - LAN9118_DRIVER *LanDriver; - UINT32 RxFifoStatus; - UINT32 NumPackets; - UINT32 RxCfgValue; - UINT32 PLength; // Packet length - UINT32 ReadLimit; - UINT32 Count; - UINT32 Padding; - UINT32 *RawData; + LAN9118_DRIVER *LanDriver; + UINT32 IntSts; + UINT32 RxFifoStatus; + UINT32 NumPackets; + UINT32 RxCfgValue; + UINT32 PLength; // Packet length + UINT32 ReadLimit; + UINT32 Count; + UINT32 Padding; + UINT32 *RawData; EFI_MAC_ADDRESS Dst; EFI_MAC_ADDRESS Src; - UINTN DroppedFrames; + UINTN DroppedFrames; + EFI_STATUS Status; LanDriver = INSTANCE_FROM_SNP_THIS (Snp); @@ -1182,16 +1324,42 @@ SnpReceive ( #endif // Check preliminaries - if ((Snp == NULL) || (Data == NULL)) { + if ((Snp == NULL) || (Data == NULL) || (BuffSize == NULL)) { return EFI_INVALID_PARAMETER; } - if (Snp->Mode->State != EfiSimpleNetworkInitialized) { + // Check that driver was started and initialised + if (Snp->Mode->State == EfiSimpleNetworkStarted) { + DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver not initialized\n")); + return EFI_DEVICE_ERROR; + } else if (Snp->Mode->State == EfiSimpleNetworkStopped) { + DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver in stopped state\n")); return EFI_NOT_STARTED; } + // + // If the receiver raised the RXE error bit, check if the receiver status + // FIFO is full and if not just acknowledge the error. The two other + // conditions to get a RXE error are : + // . the RX data FIFO is read whereas being empty. + // . the RX status FIFO is read whereas being empty. + // The RX data and status FIFO are read by this driver only in the following + // code of this function. After the readings, the RXE error bit is checked + // and if raised, the controller is reset. Thus, at this point, we consider + // that the only valid reason to get an RXE error is the receiver status + // FIFO being full. And if this is not the case, we consider that this is + // a spurious error and we just get rid of it. We experienced such 'spurious' + // errors when running the driver on an A57 on Juno. No valid reason to + // explain those errors has been found so far and everything seems to + // work perfectly when they are just ignored. + // + IntSts = Lan9118MmioRead32 (LAN9118_INT_STS); + if ((IntSts & INSTS_RXE) && (!(IntSts & INSTS_RSFF))) { + Lan9118MmioWrite32 (LAN9118_INT_STS, INSTS_RXE); + } + // Count dropped frames - DroppedFrames = MmioRead32 (LAN9118_RX_DROP); + DroppedFrames = Lan9118MmioRead32 (LAN9118_RX_DROP); LanDriver->Stats.RxDroppedFrames += DroppedFrames; NumPackets = RxStatusUsedSpace (0, Snp) / 4; @@ -1200,7 +1368,7 @@ SnpReceive ( } // Read Rx Status (only if not empty) - RxFifoStatus = MmioRead32 (LAN9118_RX_STATUS); + RxFifoStatus = Lan9118MmioRead32 (LAN9118_RX_STATUS); LanDriver->Stats.RxTotalFrames += 1; // First check for errors @@ -1256,12 +1424,6 @@ SnpReceive ( PLength = GET_RXSTATUS_PACKET_LENGTH(RxFifoStatus); LanDriver->Stats.RxTotalBytes += (PLength - 4); - // Check buffer size - if (*BuffSize < PLength) { - *BuffSize = PLength; - return EFI_BUFFER_TOO_SMALL; - } - // If padding is applied, read more DWORDs if (PLength % 4) { Padding = 4 - (PLength % 4); @@ -1271,15 +1433,21 @@ SnpReceive ( Padding = 0; } + // Check buffer size + if (*BuffSize < (PLength + Padding)) { + *BuffSize = PLength + Padding; + return EFI_BUFFER_TOO_SMALL; + } + // Set the amount of data to be transfered out of FIFO for THIS packet // This can be used to trigger an interrupt, and status can be checked - RxCfgValue = MmioRead32 (LAN9118_RX_CFG); + RxCfgValue = Lan9118MmioRead32 (LAN9118_RX_CFG); RxCfgValue &= ~(RXCFG_RX_DMA_CNT_MASK); RxCfgValue |= RXCFG_RX_DMA_CNT (ReadLimit); // Set end alignment to 4-bytes RxCfgValue &= ~(RXCFG_RX_END_ALIGN_MASK); - MmioWrite32 (LAN9118_RX_CFG, RxCfgValue); + Lan9118MmioWrite32 (LAN9118_RX_CFG, RxCfgValue); // Update buffer size *BuffSize = PLength; // -4 bytes may be needed: Received in buffer as @@ -1294,28 +1462,7 @@ SnpReceive ( // Read Rx Packet for (Count = 0; Count < ReadLimit; Count++) { - RawData[Count] = MmioRead32 (LAN9118_RX_DATA); - } - - // Check for Rx errors (worst possible error) - if (MmioRead32 (LAN9118_INT_STS) & INSTS_RXE) { - DEBUG ((EFI_D_WARN, "Warning: Receiver Error. Restarting...\n")); - - // Initiate a software reset - if (SoftReset (0, Snp) < 0) { - DEBUG ((EFI_D_ERROR, "Error: Soft Reset Failed: Hardware Error.\n")); - return EFI_DEVICE_ERROR; - } - - // Acknowledge the RXE - MmioWrite32 (LAN9118_INT_STS, INSTS_RXE); - gBS->Stall (LAN9118_STALL); - - // Restart the rx (and do not clear FIFO) - StartRx (0, Snp); - - // Say that command could not be sent - return EFI_DEVICE_ERROR; + RawData[Count] = Lan9118MmioRead32 (LAN9118_RX_DATA); } // Get the destination address @@ -1337,7 +1484,7 @@ SnpReceive ( Src.Addr[3] = (RawData[2] & 0xFF00) >> 8; Src.Addr[4] = (RawData[2] & 0xFF0000) >> 16; Src.Addr[5] = (RawData[2] & 0xFF000000) >> 24; - CopyMem (SrcAddr,&Src, NET_ETHER_ADDR_LEN); + CopyMem (SrcAddr, &Src, NET_ETHER_ADDR_LEN); } // Get the protocol @@ -1345,6 +1492,34 @@ SnpReceive ( *Protocol = NTOHS (RawData[3] & 0xFFFF); } + // Check for Rx errors (worst possible error) + if (Lan9118MmioRead32 (LAN9118_INT_STS) & INSTS_RXE) { + DEBUG ((EFI_D_WARN, "Warning: Receiver Error. Restarting...\n")); + + // Software reset, the RXE interrupt is cleared by the reset. + Status = SoftReset (0, Snp); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Error: Soft Reset Failed: Hardware Error.\n")); + return EFI_DEVICE_ERROR; + } + + // Reactivate the LEDs + Status = ConfigureHardware (HW_CONF_USE_LEDS, Snp); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Restart the receiver and the transmitter without resetting the FIFOs + // as it has been done by SoftReset(). + // + StartRx (0, Snp); + StartTx (START_TX_MAC | START_TX_CFG, Snp); + + // Say that command could not be sent + return EFI_DEVICE_ERROR; + } + #if defined(EVAL_PERFORMANCE) UINT64 EndClock = GetPerformanceCounter (); DEBUG ((EFI_D_ERROR, "Receive Time processing: %d counts @ %d Hz\n", StartClock - EndClock,Perf));