From e1e78a61254a56dd093c04b1465b335476b4f8ea Mon Sep 17 00:00:00 2001 From: Olivier Martin Date: Thu, 10 Jan 2013 11:37:12 +0000 Subject: MdeModulePkg/MnpDxe: Checked returned value of Snp->GetStatus() ... as explicitly said by the comment. Signed-off-by: Olivier Martin Change-Id: Id9fd51dd5510d6acd04fe2c323a901248c4b85c3 --- MdeModulePkg/Universal/Network/MnpDxe/MnpMain.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/MdeModulePkg/Universal/Network/MnpDxe/MnpMain.c b/MdeModulePkg/Universal/Network/MnpDxe/MnpMain.c index 4c0f3ddd9..9cdbb432e 100644 --- a/MdeModulePkg/Universal/Network/MnpDxe/MnpMain.c +++ b/MdeModulePkg/Universal/Network/MnpDxe/MnpMain.c @@ -79,8 +79,10 @@ MnpGetModeData ( // Upon successful return of GetStatus(), the Snp->Mode->MediaPresent // will be updated to reflect any change of media status // - Snp->GetStatus (Snp, &InterruptStatus, NULL); - CopyMem (SnpModeData, Snp->Mode, sizeof (*SnpModeData)); + Status = Snp->GetStatus (Snp, &InterruptStatus, NULL); + if (!EFI_ERROR (Status)) { + CopyMem (SnpModeData, Snp->Mode, sizeof (*SnpModeData)); + } } if (!Instance->Configured) { -- cgit v1.2.3 From f514468cea92785403c4b40b3678e72d3a6b0e34 Mon Sep 17 00:00:00 2001 From: Olivier Martin Date: Thu, 10 Jan 2013 11:43:23 +0000 Subject: MdeModulePkg//ArpDxe: Retrieved SnpMode only after configuring Snp When Arp driver starts (with ArpDriverBindingStart()), its service will be created and the Mnp child configured (ArpService->Mnp->Configure() called in ArpCreateService()). It is only at this time the Snp protocol will be initialized (at the end of MnpStart()). So, a valid SnpMode could not be expected prior to ArpService->Mnp->Configure(). Signed-off-by: Olivier Martin --- MdeModulePkg/Universal/Network/ArpDxe/ArpDriver.c | 33 ++++++++++++----------- 1 file changed, 17 insertions(+), 16 deletions(-) mode change 100644 => 100755 MdeModulePkg/Universal/Network/ArpDxe/ArpDriver.c diff --git a/MdeModulePkg/Universal/Network/ArpDxe/ArpDriver.c b/MdeModulePkg/Universal/Network/ArpDxe/ArpDriver.c old mode 100644 new mode 100755 index 81ddd6263..5cf717f94 --- a/MdeModulePkg/Universal/Network/ArpDxe/ArpDriver.c +++ b/MdeModulePkg/Universal/Network/ArpDxe/ArpDriver.c @@ -102,22 +102,6 @@ ArpCreateService ( goto ERROR_EXIT; } - // - // Get the underlayer Snp mode data. - // - Status = ArpService->Mnp->GetModeData (ArpService->Mnp, NULL, &ArpService->SnpMode); - if ((Status != EFI_NOT_STARTED) && EFI_ERROR (Status)) { - goto ERROR_EXIT; - } - - if (ArpService->SnpMode.IfType != NET_IFTYPE_ETHERNET) { - // - // Only support the ethernet. - // - Status = EFI_UNSUPPORTED; - goto ERROR_EXIT; - } - // // Set the Mnp config parameters. // @@ -141,6 +125,23 @@ ArpCreateService ( } // + // Get the underlayer Snp mode data. Must do this after MNP configuration else some parameters + // (e.g. current address) may not be set + // + Status = ArpService->Mnp->GetModeData (ArpService->Mnp, NULL, &ArpService->SnpMode); + if ((Status != EFI_NOT_STARTED) && EFI_ERROR (Status)) { + goto ERROR_EXIT; + } + + if (ArpService->SnpMode.IfType != NET_IFTYPE_ETHERNET) { + // + // Only support the ethernet. + // + Status = EFI_UNSUPPORTED; + goto ERROR_EXIT; + } + + // // Create the event used in the RxToken. // Status = gBS->CreateEvent ( -- cgit v1.2.3 From b742bf9a7117e77bffb3b344353c882f3d84556f Mon Sep 17 00:00:00 2001 From: Ryan Harkin Date: Fri, 24 May 2013 16:30:00 +0100 Subject: ArmPlatformPkg/ArmVExpressPkg: add network modules Add the core network components needed for networking and PXE boot. Signed-off-by: Ryan Harkin --- ArmPlatformPkg/ArmVExpressPkg/ArmVExpress.dsc.inc | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress.dsc.inc b/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress.dsc.inc index dee39aa8e..cb04012d9 100644 --- a/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress.dsc.inc +++ b/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress.dsc.inc @@ -54,6 +54,12 @@ #BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf BaseMemoryLib|ArmPkg/Library/BaseMemoryLibStm/BaseMemoryLibStm.inf + # Networking Requirements + NetLib|MdeModulePkg/Library/DxeNetLib/DxeNetLib.inf + DpcLib|MdeModulePkg/Library/DxeDpcLib/DxeDpcLib.inf + UdpIoLib|MdeModulePkg/Library/DxeUdpIoLib/DxeUdpIoLib.inf + IpIoLib|MdeModulePkg/Library/DxeIpIoLib/DxeIpIoLib.inf + # ARM Architectural Libraries CacheMaintenanceLib|ArmPkg/Library/ArmCacheMaintenanceLib/ArmCacheMaintenanceLib.inf DefaultExceptionHandlerLib|ArmPkg/Library/DefaultExceptionHandlerLib/DefaultExceptionHandlerLib.inf @@ -344,3 +350,20 @@ gArmPlatformTokenSpaceGuid.PcdDefaultConInPaths|L"VenHw(D3987D4B-971A-435F-8CAF-4967EB627241)/Uart(38400,8,N,1)/VenPcAnsi()" gArmPlatformTokenSpaceGuid.PcdPlatformBootTimeOut|10 +[Components.common] + # + # Networking stack + # + MdeModulePkg/Universal/Network/DpcDxe/DpcDxe.inf + MdeModulePkg/Universal/Network/ArpDxe/ArpDxe.inf + MdeModulePkg/Universal/Network/Dhcp4Dxe/Dhcp4Dxe.inf + MdeModulePkg/Universal/Network/Ip4ConfigDxe/Ip4ConfigDxe.inf + MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Dxe.inf + MdeModulePkg/Universal/Network/MnpDxe/MnpDxe.inf + MdeModulePkg/Universal/Network/VlanConfigDxe/VlanConfigDxe.inf + MdeModulePkg/Universal/Network/Mtftp4Dxe/Mtftp4Dxe.inf + MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Dxe.inf + MdeModulePkg/Universal/Network/Udp4Dxe/Udp4Dxe.inf + MdeModulePkg/Universal/Network/UefiPxeBcDxe/UefiPxeBcDxe.inf + MdeModulePkg/Universal/Network/IScsiDxe/IScsiDxe.inf + -- cgit v1.2.3 From ff92e9bc27ad83cbf03c9917ccb833134ec1b407 Mon Sep 17 00:00:00 2001 From: "Reece R. Pollack" Date: Wed, 25 Sep 2013 23:41:09 -0400 Subject: ArmPlatformPkg: Added LAN9118 Dxe driver Added a driver for the SMSC LAN9118 Ethernet controller, used on the baseboard of the Versatile Express reference system. Note that per-CPU support patches are committed in their respective branches rather than here. Signed-off-by: Reece R. Pollack --- ArmPlatformPkg/ArmPlatformPkg.dec | 5 + ArmPlatformPkg/ArmVExpressPkg/ArmVExpress.dsc.inc | 1 + ArmPlatformPkg/Drivers/LAN9118Dxe/LAN9118Dxe.c | 2589 +++++++++++++++++++++ ArmPlatformPkg/Drivers/LAN9118Dxe/LAN9118Dxe.inf | 55 + ArmPlatformPkg/Drivers/LAN9118Dxe/LAN9118DxeHw.h | 325 +++ 5 files changed, 2975 insertions(+) create mode 100644 ArmPlatformPkg/Drivers/LAN9118Dxe/LAN9118Dxe.c create mode 100644 ArmPlatformPkg/Drivers/LAN9118Dxe/LAN9118Dxe.inf create mode 100644 ArmPlatformPkg/Drivers/LAN9118Dxe/LAN9118DxeHw.h diff --git a/ArmPlatformPkg/ArmPlatformPkg.dec b/ArmPlatformPkg/ArmPlatformPkg.dec index 3358225ae..2c4f88801 100644 --- a/ArmPlatformPkg/ArmPlatformPkg.dec +++ b/ArmPlatformPkg/ArmPlatformPkg.dec @@ -139,6 +139,11 @@ gArmPlatformTokenSpaceGuid.PcdDefaultConInPaths|L""|VOID*|0x0000001B gArmPlatformTokenSpaceGuid.PcdDefaultConOutPaths|L""|VOID*|0x0000001C + # + # LAN9118 Ethernet Driver PCDs + # + gArmPlatformTokenSpaceGuid.PcdLan9118DxeBaseAddress|0x0|UINT32|0x000000FF + [PcdsFixedAtBuild.ARM] # Stack for CPU Cores in Secure Monitor Mode gArmPlatformTokenSpaceGuid.PcdCPUCoresSecMonStackBase|0|UINT32|0x00000007 diff --git a/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress.dsc.inc b/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress.dsc.inc index cb04012d9..fe0604bd5 100644 --- a/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress.dsc.inc +++ b/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress.dsc.inc @@ -366,4 +366,5 @@ MdeModulePkg/Universal/Network/Udp4Dxe/Udp4Dxe.inf MdeModulePkg/Universal/Network/UefiPxeBcDxe/UefiPxeBcDxe.inf MdeModulePkg/Universal/Network/IScsiDxe/IScsiDxe.inf + ArmPlatformPkg/Drivers/LAN9118Dxe/LAN9118Dxe.inf diff --git a/ArmPlatformPkg/Drivers/LAN9118Dxe/LAN9118Dxe.c b/ArmPlatformPkg/Drivers/LAN9118Dxe/LAN9118Dxe.c new file mode 100644 index 000000000..010a8e473 --- /dev/null +++ b/ArmPlatformPkg/Drivers/LAN9118Dxe/LAN9118Dxe.c @@ -0,0 +1,2589 @@ +/** @file +* +* Copyright (c) 2012-2013, 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. +* +**/ + +#include +#include +#include + +// Protocols used by this driver +#include +#include +#include +#include + +// Libraries used by this driver +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "LAN9118DxeHw.h" + +#define LAN9118_TPL TPL_CALLBACK + +// Most common CRC32 Polynomial for little endian machines +#define CRC_POLYNOMIAL 0xEDB88320 + +/* ------------------ Debug Functions ------------------ */ + +// Flags for printing register values +#define PRINT_REGISTERS_MAC BIT0 +#define PRINT_REGISTERS_PHY BIT1 +#define PRINT_REGISTERS_ALL (BIT0 | BIT1) +#define PRINT_REGISTERS_SEL_MAC BIT12 +#define PRINT_REGISTERS_SEL_PHY BIT13 + + +/* ------------------ MAC CSR Access ------------------- */ + + +// Flags for software reset +#define SOFT_RESET_CHECK_MAC_ADDR_LOAD BIT0 +#define SOFT_RESET_CLEAR_INT BIT1 +#define SOFT_RESET_SELF_TEST BIT2 + +// Flags for PHY reset +#define PHY_RESET_PMT BIT0 +#define PHY_RESET_BCR BIT1 +#define PHY_RESET_CHECK_LINK BIT2 +#define PHY_SOFT_RESET_CLEAR_INT BIT3 + +// Flags for Hardware configuration +#define HW_CONF_USE_LEDS BIT0 + +// Stop transmitter flags +#define STOP_TX_MAC BIT0 +#define STOP_TX_CFG BIT1 +#define STOP_TX_CLEAR BIT2 + +// Stop receiver flags +#define STOP_RX_CLEAR BIT0 + +// Start transmitter flags +#define START_TX_MAC BIT0 +#define START_TX_CFG BIT1 +#define START_TX_CLEAR BIT2 + +// Stop receiver flags +#define START_RX_CLEAR BIT0 + +// Flags for FIFO allocation +#define ALLOC_USE_DEFAULT 0x00000001 +#define ALLOC_USE_FIFOS 0x00000002 +#define ALLOC_USE_DMA 0x00000004 + +// FIFO min and max sizes +#define TX_FIFO_MIN_SIZE 0x00000600 +#define TX_FIFO_MAX_SIZE 0x00003600 +//#define RX_FIFO_MIN_SIZE +//#define RX_FIFO_MAX_SIZE +#define LAN9118_STALL 2 + +#define LAN9118_DEFAULT_MAC_ADDRL 0x00F70200 +#define LAN9118_DEFAULT_MAC_ADDRH 0x00009040 + +/*--------------------------------------------------------------------------------------------------------------------- + + LAN9118 Information Structure + +---------------------------------------------------------------------------------------------------------------------*/ + +#define LAN9118_TX_CACHE_DEPTH 16 + +// TxCache management structure +typedef struct { + VOID *buffadr; + UINTN refcount; +} LAN9118_TX_CACHE; + +typedef struct { + // Driver signature + UINT32 Signature; + EFI_HANDLE ControllerHandle; + + // EFI SNP protocol instances + EFI_SIMPLE_NETWORK_PROTOCOL Snp; + EFI_SIMPLE_NETWORK_MODE SnpMode; + + // EFI Snp statistics instance + EFI_NETWORK_STATISTICS Stats; + + // Transmit Completion Cache + VOID *TxCache[LAN9118_TX_CACHE_DEPTH]; +} LAN9118_DRIVER; + +#define LAN9118_SIGNATURE SIGNATURE_32('l', 'a', 'n', '9') +#define INSTANCE_FROM_SNP_THIS(a) CR(a, LAN9118_DRIVER, Snp, LAN9118_SIGNATURE) + + +typedef struct { + MAC_ADDR_DEVICE_PATH Lan9118; + EFI_DEVICE_PATH_PROTOCOL End; +} LAN9118_DEVICE_PATH; + +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 + }, + { + END_DEVICE_PATH_TYPE, + END_ENTIRE_DEVICE_PATH_SUBTYPE, + sizeof(EFI_DEVICE_PATH_PROTOCOL), + 0 + } +}; + +/** + This internal function reverses bits for 32bit data. + + @param Value The data to be reversed. + + @return Data reversed. + +**/ +UINT32 +ReverseBits ( + UINT32 Value + ) +{ + UINTN Index; + UINT32 NewValue; + + NewValue = 0; + for (Index = 0; Index < 32; Index++) { + if ((Value & (1 << Index)) != 0) { + NewValue = NewValue | (1 << (31 - Index)); + } + } + + return NewValue; +} + +/* +** Create Ethernet CRC +** +** INFO USED: +** 1: http://en.wikipedia.org/wiki/Cyclic_redundancy_check +** +** 2: http://www.erg.abdn.ac.uk/~gorry/eg3567/dl-pages/crc.html +** +** 3: http://en.wikipedia.org/wiki/Computation_of_CRC +*/ +UINT32 +GenEtherCrc32 ( + IN EFI_MAC_ADDRESS *Mac, + IN UINT32 AddrLen + ) +{ + INT32 Iter; + UINT32 Remainder; + UINT8 *Ptr; + + Iter = 0; + Remainder = 0xFFFFFFFF; // 0xFFFFFFFF is standard seed for Ethernet + + // Convert Mac Address to array of bytes + Ptr = (UINT8*)Mac; + + // Generate the Crc bit-by-bit (LSB first) + while (AddrLen--) { + Remainder ^= *Ptr++; + for (Iter = 0;Iter < 8;Iter++) { + // Check if exponent is set + if (Remainder & 1) { + Remainder = (Remainder >> 1) ^ CRC_POLYNOMIAL; + } else { + Remainder = (Remainder >> 1) ^ 0; + } + } + } + + // Reverse the bits before returning (to Big Endian) + return ReverseBits (Remainder); +} + +STATIC CONST CHAR16 *Mac2Str (EFI_MAC_ADDRESS *Mac) +{ + static CHAR16 MacStr[18]; + + if (Mac == NULL) { + return L""; + } + + UnicodeSPrintAsciiFormat (MacStr, sizeof(MacStr), + "%02x:%02x:%02x:%02x:%02x:%02x", + Mac->Addr[0], Mac->Addr[1], Mac->Addr[2], + Mac->Addr[3], Mac->Addr[4], Mac->Addr[5]); + return MacStr; +} + +// Function to read from MAC indirect registers +UINT32 +IndirectMACRead32 ( + UINT32 Index + ) +{ + UINT32 MacCSR; + + // Check index is in the range + ASSERT(Index <= 12); + + // Wait until CSR busy bit is cleared + while ((MmioRead32 (LAN9118_MAC_CSR_CMD) & MAC_CSR_BUSY) == MAC_CSR_BUSY); + + // Set CSR busy bit to ensure read will occur + // Set the R/W bit to indicate we are reading + // Set the index of CSR Address to access desired register + MacCSR = MAC_CSR_BUSY | MAC_CSR_READ | MAC_CSR_ADDR(Index); + + // Write to the register + MmioWrite32 (LAN9118_MAC_CSR_CMD, MacCSR); + + // Wait until CSR busy bit is cleared + while ((MmioRead32 (LAN9118_MAC_CSR_CMD) & MAC_CSR_BUSY) == MAC_CSR_BUSY); + + // Now read from data register to get read value + return MmioRead32 (LAN9118_MAC_CSR_DATA); +} + +// Function to write to MAC indirect registers +UINT32 +IndirectMACWrite32 ( + UINT32 Index, + UINT32 Value + ) +{ + UINT32 ValueWritten; + UINT32 MacCSR; + + // Check index is in the range + ASSERT(Index <= 12); + + // Wait until CSR busy bit is cleared + while ((MmioRead32 (LAN9118_MAC_CSR_CMD) & MAC_CSR_BUSY) == MAC_CSR_BUSY); + + // Set CSR busy bit to ensure read will occur + // Set the R/W bit to indicate we are writing + // Set the index of CSR Address to access desired register + MacCSR = MAC_CSR_BUSY | MAC_CSR_WRITE | MAC_CSR_ADDR(Index); + + // Now write the value to the register before issuing the write command + ValueWritten = MmioWrite32 (LAN9118_MAC_CSR_DATA, Value); + + // Write the config to the register + MmioWrite32 (LAN9118_MAC_CSR_CMD, MacCSR); + + // Wait until CSR busy bit is cleared + while ((MmioRead32 (LAN9118_MAC_CSR_CMD) & MAC_CSR_BUSY) == MAC_CSR_BUSY); + + return ValueWritten; +} + +// Function to read from MII register (PHY Access) +UINT32 +IndirectPHYRead32 ( + UINT32 Index + ) +{ + UINT32 ValueRead; + UINT32 MiiAcc; + + // Check it is a valid index + ASSERT(Index < 31); + + // Wait for busy bit to clear + while ((IndirectMACRead32 (INDIRECT_MAC_INDEX_MII_ACC) & MII_ACC_MII_BUSY) == MII_ACC_MII_BUSY); + + // Clear the R/W bit to indicate we are reading + // Set the index of the MII register + // Set the PHY Address + // Set the MII busy bit to allow read + MiiAcc = MII_ACC_MII_READ | MII_ACC_MII_REG_INDEX(Index) | MII_ACC_PHY_VALUE | MII_ACC_MII_BUSY; + + // Now write this config to register + IndirectMACWrite32 (INDIRECT_MAC_INDEX_MII_ACC, MiiAcc & 0xFFFF); + + // Wait for busy bit to clear + while ((IndirectMACRead32 (INDIRECT_MAC_INDEX_MII_ACC) & MII_ACC_MII_BUSY) == MII_ACC_MII_BUSY); + + // Now read the value of the register + ValueRead = (IndirectMACRead32 (INDIRECT_MAC_INDEX_MII_DATA) & 0xFFFF); // only lower 16 bits are valid for any PHY register + + return ValueRead; +} + + +// Function to write to the MII register (PHY Access) +UINT32 +IndirectPHYWrite32 ( + UINT32 Index, + UINT32 Value + ) +{ + UINT32 MiiAcc; + UINT32 ValueWritten; + + // Check it is a valid index + ASSERT(Index < 31); + + // Wait for busy bit to clear + while ((IndirectMACRead32 (INDIRECT_MAC_INDEX_MII_ACC) & MII_ACC_MII_BUSY) == MII_ACC_MII_BUSY); + + // Clear the R/W bit to indicate we are reading + // Set the index of the MII register + // Set the PHY Address + // Set the MII busy bit to allow read + MiiAcc = MII_ACC_MII_WRITE | MII_ACC_MII_REG_INDEX(Index) | MII_ACC_PHY_VALUE | MII_ACC_MII_BUSY; + + // Write the desired value to the register first + ValueWritten = IndirectMACWrite32 (INDIRECT_MAC_INDEX_MII_DATA, (Value & 0xFFFF)); + + // Now write the config to register + IndirectMACWrite32 (INDIRECT_MAC_INDEX_MII_ACC, MiiAcc & 0xFFFF); + + // Wait for operation to terminate + while ((IndirectMACRead32 (INDIRECT_MAC_INDEX_MII_ACC) & MII_ACC_MII_BUSY) == MII_ACC_MII_BUSY); + + return ValueWritten; +} + + +// DEBUG: Print all register values +UINT32 +PrintRegisters ( + IN UINT32 Flags, + IN EFI_SIMPLE_NETWORK_PROTOCOL *Snp + ) +{ + UINT32 Count; + UINT32 RegValue; + + // Select MAC register if defined (5 LSBs select register) + if (Flags & PRINT_REGISTERS_SEL_MAC) { + RegValue = IndirectMACRead32 (Flags & 0x1FF); + DEBUG((EFI_D_ERROR, "MAC Register %02x:\thex: 0x%08x\n",Flags & 0x1FF, RegValue)); + return 0; + } + + // Select PHY register if defined (5 LSBs select register) + if (Flags & PRINT_REGISTERS_SEL_PHY) { + RegValue = IndirectPHYRead32 (Flags & 0x1FF); + DEBUG((EFI_D_ERROR, "PHY Register %d:\thex: 0x%08x\n",Flags & 0x1FF, RegValue)); + return 0; + } + + // Loop through all MAC registers + if (Flags & PRINT_REGISTERS_MAC) { + for (Count = 1;Count <= 0xC;Count++) { + RegValue = IndirectMACRead32 (Count); + DEBUG((EFI_D_ERROR, "MAC Register %02x:\thex: 0x%08x\n", Count, RegValue)); + } + } + + // Print PHY registers + if (Flags & PRINT_REGISTERS_PHY) { + for (Count = 0;Count <= 6;Count ++) { + RegValue = IndirectPHYRead32 (Count); + DEBUG((EFI_D_ERROR, "PHY Register %d:\thex: 0x%08x\n", Count, RegValue)); + } + + Count = 17; + RegValue = IndirectPHYRead32 (Count); + DEBUG((EFI_D_ERROR, "PHY Register %d:\thex: 0x%08x\n", Count, RegValue)); + + Count = 18; + RegValue = IndirectPHYRead32 (Count); + DEBUG((EFI_D_ERROR, "PHY Register %d:\thex: 0x%08x\n", Count, RegValue)); + + Count = 27; + RegValue = IndirectPHYRead32 (Count); + DEBUG((EFI_D_ERROR, "PHY Register %d:\thex: 0x%08x\n", Count, RegValue)); + + Count = 29; + RegValue = IndirectPHYRead32 (Count); + DEBUG((EFI_D_ERROR, "PHY Register %d:\thex: 0x%08x\n", Count, RegValue)); + + Count = 30; + RegValue = IndirectPHYRead32 (Count); + DEBUG((EFI_D_ERROR, "PHY Register %d:\thex: 0x%08x\n", Count, RegValue)); + + Count = 31; + RegValue = IndirectPHYRead32 (Count); + DEBUG((EFI_D_ERROR, "PHY Register %d:\thex: 0x%08x\n", Count, RegValue)); + } + + return 0; +} + + +/* ---------------- EEPROM Operations ------------------ */ + + +// Function to read from EEPROM memory +UINT32 +IndirectEEPROMRead32 ( + UINT32 Index +) +{ + // Eeprom command + UINT32 EepromCmd = 0;//= MmioRead32 (LAN9118_E2P_CMD); + + // Set the busy bit to ensure read will occur + EepromCmd |= ((UINT32)1 << 31); + + // Set the EEPROM command to read(0b000) + EepromCmd &= ~(0x70000000); // Clear the command first + EepromCmd |= (0 << 28); // Not necessary, but here for clarity + + // Set the index to access desired EEPROM memory location + EepromCmd |= (Index & 0xF); + + // Write to Eeprom command register + MmioWrite32 (LAN9118_E2P_CMD, EepromCmd); + gBS->Stall (LAN9118_STALL); + + // Wait until operation has completed + while (MmioRead32 (LAN9118_E2P_CMD) & E2P_EPC_BUSY); + + // Check that operation didn't time out + if (MmioRead32 (LAN9118_E2P_CMD) & E2P_EPC_TIMEOUT) { + DEBUG((EFI_D_ERROR, "EEPROM Operation Timed out: Read command on index %x\n",Index)); + return 0; + } + + // Wait until operation has completed + while (MmioRead32 (LAN9118_E2P_CMD) & E2P_EPC_BUSY); + + // Finally read the value + return MmioRead32 (LAN9118_E2P_DATA); +} + +// Function to write to EEPROM memory +UINT32 +IndirectEEPROMWrite32 ( + UINT32 Index, + UINT32 Value + ) +{ + UINT32 ValueWritten; + UINT32 EepromCmd; + + ValueWritten = 0; + + // Read the EEPROM Command register + EepromCmd = MmioRead32 (LAN9118_E2P_CMD); + + // Set the busy bit to ensure read will occur + EepromCmd |= ((UINT32)1 << 31); + + // Set the EEPROM command to write(0b011) + EepromCmd &= ~(0x70000000); // Clear the command first + EepromCmd |= (3 << 28); // Write 011 + + // Set the index to access desired EEPROM memory location + EepromCmd |= (Index & 0xF); + + // Write the value to the data register first + ValueWritten = MmioWrite32 (LAN9118_E2P_DATA, Value); + + // Write to Eeprom command register + MmioWrite32 (LAN9118_E2P_CMD, EepromCmd); + gBS->Stall (LAN9118_STALL); + + // Wait until operation has completed + while (MmioRead32 (LAN9118_E2P_CMD) & E2P_EPC_BUSY); + + // Check that operation didn't time out + if (MmioRead32 (LAN9118_E2P_CMD) & E2P_EPC_TIMEOUT) { + DEBUG((EFI_D_ERROR, "EEPROM Operation Timed out: Write command at memloc 0x%x, with value 0x%x\n",Index, Value)); + return 0; + } + + // Wait until operation has completed + while (MmioRead32 (LAN9118_E2P_CMD) & E2P_EPC_BUSY); + + return ValueWritten; +} + +/* ---------------- General Operations ----------------- */ + + +// Stop the transmitter +EFI_STATUS +StopTx ( + UINT32 Flags, + EFI_SIMPLE_NETWORK_PROTOCOL *Snp + ) +{ + UINT32 MacCsr; + UINT32 TxCfg; + + MacCsr = 0; + TxCfg = 0; + + // Check if we want to clear tx + if (Flags & STOP_TX_CLEAR) { + TxCfg = MmioRead32 (LAN9118_TX_CFG); + TxCfg |= TXCFG_TXS_DUMP | TXCFG_TXD_DUMP; + MmioWrite32 (LAN9118_TX_CFG, TxCfg); + gBS->Stall (LAN9118_STALL); + } + + // Check if already stopped + if (Flags & STOP_TX_MAC) { + MacCsr = IndirectMACRead32 (INDIRECT_MAC_INDEX_CR); + + if (MacCsr & MACCR_TX_EN) { + MacCsr &= ~MACCR_TX_EN; + IndirectMACWrite32 (INDIRECT_MAC_INDEX_CR, MacCsr); + } + } + + if (Flags & STOP_TX_CFG) { + TxCfg = MmioRead32 (LAN9118_TX_CFG); + + if (TxCfg & TXCFG_TX_ON) { + TxCfg |= TXCFG_STOP_TX; + MmioWrite32 (LAN9118_TX_CFG, TxCfg); + gBS->Stall (LAN9118_STALL); + + // Wait for Tx to finish transmitting + while (MmioRead32 (LAN9118_TX_CFG) & TXCFG_STOP_TX); + } + } + + return EFI_SUCCESS; +} + +// Stop the receiver +EFI_STATUS +StopRx ( + UINT32 Flags, + EFI_SIMPLE_NETWORK_PROTOCOL *Snp + ) +{ + UINT32 MacCsr; + UINT32 RxCfg; + + RxCfg = 0; + + // Check if already stopped + MacCsr = IndirectMACRead32 (INDIRECT_MAC_INDEX_CR); + + if (MacCsr & MACCR_RX_EN) { + MacCsr &= ~ MACCR_RX_EN; + IndirectMACWrite32 (INDIRECT_MAC_INDEX_CR, MacCsr); + } + + // Check if we want to clear receiver FIFOs + if (Flags & STOP_RX_CLEAR) { + RxCfg = MmioRead32 (LAN9118_RX_CFG); + RxCfg |= RXCFG_RX_DUMP; + MmioWrite32 (LAN9118_RX_CFG, RxCfg); + gBS->Stall (LAN9118_STALL); + + while (MmioRead32 (LAN9118_RX_CFG) & RXCFG_RX_DUMP); + } + + return EFI_SUCCESS; +} + +// Perform software reset on the LAN9118 +// Return 0 on success, -1 on error +EFI_STATUS +SoftReset ( + UINT32 Flags, + EFI_SIMPLE_NETWORK_PROTOCOL *Snp + ) +{ + UINT32 HwConf; + UINT32 ResetTime; + + // Stop Rx and Tx + StopTx (STOP_TX_MAC | STOP_TX_CFG | STOP_TX_CLEAR, Snp); + StopRx (STOP_RX_CLEAR, Snp); // Clear receiver FIFO + + // Issue the reset + HwConf = MmioRead32 (LAN9118_HW_CFG); + HwConf |= HWCFG_SRST | HWCFG_MBO; + + // Check that EEPROM isn't active + while (MmioRead32 (LAN9118_E2P_CMD) & E2P_EPC_BUSY); + + // Write the configuration + MmioWrite32 (LAN9118_HW_CFG, HwConf); + gBS->Stall (LAN9118_STALL); + + // Wait for reset to complete + ResetTime = 1000; + while (MmioRead32 (LAN9118_HW_CFG) & HWCFG_SRST) { + + gBS->Stall (LAN9118_STALL); + + // If time taken exceeds 1000us, then there was an error condition + if (--ResetTime == 0) { + Snp->Mode->State = EfiSimpleNetworkStopped; + return EFI_TIMEOUT; + } + } + + // Check that MAC Address loaded successfully (if required) + if (Flags & SOFT_RESET_CHECK_MAC_ADDR_LOAD) { + if ((MmioRead32 (LAN9118_E2P_CMD) & E2P_EPC_MAC_ADDRESS_LOADED) == 0) { + DEBUG((EFI_D_ERROR, "Warning: There was an error detecting EEPROM or loading the MAC Address:\n" + " Using hard-coded MAC Address.\n")); + + IndirectMACWrite32 (INDIRECT_MAC_INDEX_ADDRL, LAN9118_DEFAULT_MAC_ADDRL); + IndirectMACWrite32 (INDIRECT_MAC_INDEX_ADDRH, LAN9118_DEFAULT_MAC_ADDRH); + } + } + + // Check that EEPROM isn't active + while (MmioRead32 (LAN9118_E2P_CMD) & E2P_EPC_BUSY); + + // Clear and acknowledge all interrupts + if (Flags & SOFT_RESET_CLEAR_INT) { + MmioWrite32 (LAN9118_INT_EN, 0); + MmioWrite32 (LAN9118_IRQ_CFG, 0); + MmioWrite32 (LAN9118_INT_STS, 0xFFFFFFFF); + } + + // Do self tests here? + if (Flags & SOFT_RESET_SELF_TEST) { + + } + + return EFI_SUCCESS; +} + + +// Check the Link Status and take appropriate action +BOOLEAN +CheckLinkStatus ( + EFI_SIMPLE_NETWORK_PROTOCOL *Snp + ) +{ + UINT32 PhyBStatus; + + // Get the PHY Status + PhyBStatus = IndirectPHYRead32 (PHY_INDEX_BASIC_STATUS); + + return (PhyBStatus & PHYSTS_LINK_STS) != 0; +} + +// Perform PHY software reset +INT32 +PhySoftReset ( + UINT32 Flags, + EFI_SIMPLE_NETWORK_PROTOCOL *Snp + ) +{ + UINT32 PmtCtrl = 0; + UINT32 LinkTo = 0; + + // PMT PHY reset takes precedence over BCR + if (Flags & PHY_RESET_PMT) { + PmtCtrl = MmioRead32 (LAN9118_PMT_CTRL); + PmtCtrl |= MPTCTRL_PHY_RST; + MmioWrite32 (LAN9118_PMT_CTRL,PmtCtrl); + + // Wait for completion + while (MmioRead32 (LAN9118_PMT_CTRL) & MPTCTRL_PHY_RST) { + gBS->Stall (LAN9118_STALL); + } + // PHY Basic Control Register reset + } else if (Flags & PHY_RESET_PMT) { + IndirectPHYWrite32 (PHY_INDEX_BASIC_CTRL, PHYCR_RESET); + + // Wait for completion + while (IndirectPHYRead32 (PHY_INDEX_BASIC_CTRL) & PHYCR_RESET) { + gBS->Stall (LAN9118_STALL); + } + } + + // Check the link status + if (Flags & PHY_RESET_CHECK_LINK) { + LinkTo = 100000; // 2 second (could be 50% more) + while (!CheckLinkStatus(Snp) && (LinkTo > 0)) { + gBS->Stall (LAN9118_STALL); + LinkTo--; + } + + // Timed out + if (LinkTo <= 0) { + return -1; + } + } + + // Clear and acknowledge all interrupts + if (Flags & PHY_SOFT_RESET_CLEAR_INT) { + MmioWrite32 (LAN9118_INT_EN, 0); + MmioWrite32 (LAN9118_IRQ_CFG, 0); + MmioWrite32 (LAN9118_INT_STS, 0xFFFFFFFF); + } + + return 0; +} + + +// Configure hardware for LAN9118 +EFI_STATUS +ConfigureHardware ( + UINT32 Flags, + EFI_SIMPLE_NETWORK_PROTOCOL *Snp + ) +{ + UINT32 GpioConf; + + // Check if we want to use LEDs on GPIO + if (Flags & HW_CONF_USE_LEDS) { + GpioConf = MmioRead32 (LAN9118_GPIO_CFG); + + // Enable GPIO as LEDs and Config as Push-Pull driver + GpioConf |= GPIO_GPIO0_PUSH_PULL | GPIO_GPIO1_PUSH_PULL | GPIO_GPIO2_PUSH_PULL | + GPIO_LED1_ENABLE | GPIO_LED2_ENABLE | GPIO_LED3_ENABLE; + + // Write the configuration + MmioWrite32 (LAN9118_GPIO_CFG, GpioConf); + gBS->Stall (LAN9118_STALL); + } + + return EFI_SUCCESS; +} + +// Configure flow control +EFI_STATUS +ConfigureFlow ( + UINT32 Flags, + UINT32 HighTrig, + UINT32 LowTrig, + UINT32 BPDuration, + EFI_SIMPLE_NETWORK_PROTOCOL *Snp + ) +{ + return EFI_SUCCESS; +} + +// Do auto-negotiation +EFI_STATUS +AutoNegotiate ( + EFI_SIMPLE_NETWORK_PROTOCOL *Snp + ) +{ + UINTN Retries; + UINT32 PhyControl; + UINT32 PhyStatus; + UINT32 PhyAdvert; + + // First check that auto-negotiation is supported + PhyStatus = IndirectPHYRead32 (PHY_INDEX_BASIC_STATUS); + if ((PhyStatus & PHYSTS_AUTO_CAP) == 0) { + return EFI_SUCCESS; + } + + // Translate capabilities to advertise + PhyAdvert = PHYANA_CSMA; + + if ((PhyStatus & PHYSTS_10BASET_HDPLX) != 0) { + PhyAdvert |= PHYANA_10BASET; + } + if ((PhyStatus & PHYSTS_10BASET_FDPLX) != 0) { + PhyAdvert |= PHYANA_10BASETFD; + } + if ((PhyStatus & PHYSTS_100BASETX_HDPLX) != 0) { + PhyAdvert |= PHYANA_100BASETX; + } + if ((PhyStatus & PHYSTS_100BASETX_FDPLX) != 0) { + PhyAdvert |= PHYANA_100BASETXFD; + } + if ((PhyStatus & PHYSTS_100BASE_T4) != 0) { + PhyAdvert |= PHYANA_100BASET4; + } + + // Write the features + IndirectPHYWrite32 (PHY_INDEX_AUTO_NEG_ADVERT, PhyAdvert); + + // Restart Auto-Negotiation + PhyControl = IndirectPHYRead32 (PHY_INDEX_BASIC_CTRL); + PhyControl &= ~(PHYCR_SPEED_SEL | PHYCR_DUPLEX_MODE); + PhyControl |= PHYCR_AUTO_EN | PHYCR_RST_AUTO; + IndirectPHYWrite32 (PHY_INDEX_BASIC_CTRL, PhyControl); + + // Wait up to 2 seconds for the process to complete + Retries = 2000000; + while ((IndirectPHYRead32 (PHY_INDEX_BASIC_STATUS) & PHYSTS_AUTO_COMP) == 0) { + if (--Retries == 0) { + DEBUG((EFI_D_ERROR, "LAN9118: PHY auto-negotiation timed-out\n")); + return EFI_TIMEOUT; + } + gBS->Stall (100); + } + + return EFI_SUCCESS; +} + +// Start the transmitter +EFI_STATUS +StartTx ( + EFI_SIMPLE_NETWORK_PROTOCOL *Snp + ) +{ + LAN9118_DRIVER *LanDriver; + UINT32 MacCsr; + UINT32 TxCfg; + + // Clear the transmitter + TxCfg = MmioRead32 (LAN9118_TX_CFG); + TxCfg |= TXCFG_TXS_DUMP | TXCFG_TXD_DUMP; + MmioWrite32 (LAN9118_TX_CFG, TxCfg); + gBS->Stall (LAN9118_STALL); + + // Clear the TxCache + LanDriver = INSTANCE_FROM_SNP_THIS(Snp); + ZeroMem (LanDriver->TxCache, sizeof(LanDriver->TxCache)); + + // Start the MAC + MacCsr = IndirectMACRead32 (INDIRECT_MAC_INDEX_CR); + gBS->Stall (LAN9118_STALL); + if ((MacCsr & MACCR_TX_EN) == 0) { + MacCsr |= MACCR_TX_EN; + IndirectMACWrite32 (INDIRECT_MAC_INDEX_CR, MacCsr); + gBS->Stall (LAN9118_STALL); + } + + // Enable the transmitter + TxCfg = MmioRead32 (LAN9118_TX_CFG); + gBS->Stall (LAN9118_STALL); + if ((TxCfg & TXCFG_TX_ON) == 0) { + TxCfg |= TXCFG_TX_ON; + MmioWrite32 (LAN9118_TX_CFG, TxCfg); + gBS->Stall (LAN9118_STALL); + } + + // Set the tx data trigger level + + return EFI_SUCCESS; +} + + +// Start the receiver +EFI_STATUS +StartRx ( + UINT32 Flags, + EFI_SIMPLE_NETWORK_PROTOCOL *Snp + ) +{ + UINT32 MacCsr; + UINT32 RxCfg; + + RxCfg = 0; + + // Check if already started + MacCsr = IndirectMACRead32 (INDIRECT_MAC_INDEX_CR); + + if ((MacCsr & MACCR_RX_EN) == 0) { + // Check if we want to clear receiver FIFOs before starting + if (Flags & START_RX_CLEAR) { + RxCfg = MmioRead32 (LAN9118_RX_CFG); + RxCfg |= RXCFG_RX_DUMP; + MmioWrite32 (LAN9118_RX_CFG, RxCfg); + gBS->Stall (LAN9118_STALL); + + while (MmioRead32 (LAN9118_RX_CFG) & RXCFG_RX_DUMP); + } + + MacCsr |= MACCR_RX_EN; + IndirectMACWrite32 (INDIRECT_MAC_INDEX_CR, MacCsr); + gBS->Stall (LAN9118_STALL); + } + + return EFI_SUCCESS; +} + +// Check Tx Data available space +UINT32 +TxDataFreeSpace ( + EFI_SIMPLE_NETWORK_PROTOCOL *Snp + ) +{ + UINT32 TxInf; + UINT32 FreeSpace; + + // Get the amount of free space from information register + TxInf = MmioRead32 (LAN9118_TX_FIFO_INF); + FreeSpace = (TxInf & TXFIFOINF_TDFREE_MASK); + + return FreeSpace; // Value in bytes +} + +// Check Tx Status used space +UINT32 +TxStatusUsedSpace ( + EFI_SIMPLE_NETWORK_PROTOCOL *Snp + ) +{ + UINT32 TxInf; + UINT32 UsedSpace; + + // Get the amount of used space from information register + TxInf = MmioRead32 (LAN9118_TX_FIFO_INF); + UsedSpace = (TxInf & TXFIFOINF_TXSUSED_MASK) >> 16; + + return UsedSpace; +} + +// Check Rx Data used space +UINT32 +RxDataUsedSpace ( + UINT32 Flags, + EFI_SIMPLE_NETWORK_PROTOCOL *Snp + ) +{ + UINT32 RxInf; + UINT32 UsedSpace; + + // Get the amount of used space from information register + RxInf = MmioRead32 (LAN9118_RX_FIFO_INF); + UsedSpace = (RxInf & RXFIFOINF_RXDUSED_MASK); + + return UsedSpace; // Value in bytes (rounded up to nearest DWORD) +} + +// Check Rx Status used space +UINT32 +RxStatusUsedSpace ( + UINT32 Flags, + EFI_SIMPLE_NETWORK_PROTOCOL *Snp + ) +{ + UINT32 RxInf; + UINT32 UsedSpace; + + // Get the amount of used space from information register + RxInf = MmioRead32 (LAN9118_RX_FIFO_INF); + UsedSpace = (RxInf & RXFIFOINF_RXSUSED_MASK) >> 16; + + return UsedSpace << 2; // Value in bytes +} + + +// Change the allocation of FIFOs +EFI_STATUS +ChangeFifoAllocation ( + IN UINT32 Flags, + IN OUT UINTN *TxDataSize OPTIONAL, + IN OUT UINTN *RxDataSize OPTIONAL, + IN OUT UINT32 *TxStatusSize OPTIONAL, + IN OUT UINT32 *RxStatusSize OPTIONAL, + IN OUT EFI_SIMPLE_NETWORK_PROTOCOL *Snp + ) +{ + UINT32 HwConf; + UINT32 TxFifoOption; + + // Check that desired sizes don't exceed limits + if (*TxDataSize > TX_FIFO_MAX_SIZE) + return EFI_INVALID_PARAMETER; + +#if defined(RX_FIFO_MIN_SIZE) && defined(RX_FIFO_MAX_SIZE) + if (*RxDataSize > RX_FIFO_MAX_SIZE) { + return EFI_INVALID_PARAMETER; + } +#endif + + if (Flags & ALLOC_USE_DEFAULT) { + return EFI_SUCCESS; + } + + // If we use the FIFOs (always use this first) + if (Flags & ALLOC_USE_FIFOS) { + // Read the current value of allocation + HwConf = MmioRead32 (LAN9118_HW_CFG); + TxFifoOption = (HwConf >> 16) & 0xF; + + // Choose the correct size (always use larger than requested if possible) + if (*TxDataSize < TX_FIFO_MIN_SIZE) { + *TxDataSize = TX_FIFO_MIN_SIZE; + *RxDataSize = 13440; + *RxStatusSize = 896; + TxFifoOption = 2; + } else if ((*TxDataSize > TX_FIFO_MIN_SIZE) && (*TxDataSize <= 2560)) { + *TxDataSize = 2560; + *RxDataSize = 12480; + *RxStatusSize = 832; + TxFifoOption = 3; + } else if ((*TxDataSize > 2560) && (*TxDataSize <= 3584)) { + *TxDataSize = 3584; + *RxDataSize = 11520; + *RxStatusSize = 768; + TxFifoOption = 4; + } else if ((*TxDataSize > 3584) && (*TxDataSize <= 4608)) { // default option + *TxDataSize = 4608; + *RxDataSize = 10560; + *RxStatusSize = 704; + TxFifoOption = 5; + } else if ((*TxDataSize > 4608) && (*TxDataSize <= 5632)) { + *TxDataSize = 5632; + *RxDataSize = 9600; + *RxStatusSize = 640; + TxFifoOption = 6; + } else if ((*TxDataSize > 5632) && (*TxDataSize <= 6656)) { + *TxDataSize = 6656; + *RxDataSize = 8640; + *RxStatusSize = 576; + TxFifoOption = 7; + } else if ((*TxDataSize > 6656) && (*TxDataSize <= 7680)) { + *TxDataSize = 7680; + *RxDataSize = 7680; + *RxStatusSize = 512; + TxFifoOption = 8; + } else if ((*TxDataSize > 7680) && (*TxDataSize <= 8704)) { + *TxDataSize = 8704; + *RxDataSize = 6720; + *RxStatusSize = 448; + TxFifoOption = 9; + } else if ((*TxDataSize > 8704) && (*TxDataSize <= 9728)) { + *TxDataSize = 9728; + *RxDataSize = 5760; + *RxStatusSize = 384; + TxFifoOption = 10; + } else if ((*TxDataSize > 9728) && (*TxDataSize <= 10752)) { + *TxDataSize = 10752; + *RxDataSize = 4800; + *RxStatusSize = 320; + TxFifoOption = 11; + } else if ((*TxDataSize > 10752) && (*TxDataSize <= 11776)) { + *TxDataSize = 11776; + *RxDataSize = 3840; + *RxStatusSize = 256; + TxFifoOption = 12; + } else if ((*TxDataSize > 11776) && (*TxDataSize <= 12800)) { + *TxDataSize = 12800; + *RxDataSize = 2880; + *RxStatusSize = 192; + TxFifoOption = 13; + } else if ((*TxDataSize > 12800) && (*TxDataSize <= 13824)) { + *TxDataSize = 13824; + *RxDataSize = 1920; + *RxStatusSize = 128; + TxFifoOption = 14; + } + } else { + ASSERT(0); // Untested code path + HwConf = 0; + TxFifoOption = 0; + } + + // Do we need DMA? + if (Flags & ALLOC_USE_DMA) { + return EFI_UNSUPPORTED; // Unsupported as of now + } + // Clear and assign the new size option + HwConf &= ~(0xF0000); + HwConf |= ((TxFifoOption & 0xF) << 16); + MmioWrite32 (LAN9118_HW_CFG, HwConf); + gBS->Stall (LAN9118_STALL); + + return EFI_SUCCESS; +} + +/*--------------------------------------------------------------------------------------------------------------------- + + Utility functions + +---------------------------------------------------------------------------------------------------------------------*/ + +EFI_MAC_ADDRESS +GetCurrentMacAddress ( + VOID + ) +{ + UINT32 MacAddrHighValue; + UINT32 MacAddrLowValue; + EFI_MAC_ADDRESS MacAddress; + + // Read the Mac Addr high register + MacAddrHighValue = (IndirectMACRead32 (INDIRECT_MAC_INDEX_ADDRH) & 0xFFFF); + // Read the Mac Addr low register + MacAddrLowValue = IndirectMACRead32 (INDIRECT_MAC_INDEX_ADDRL); + + SetMem (&MacAddress, sizeof(MacAddress), 0); + MacAddress.Addr[0] = (MacAddrLowValue & 0xFF); + MacAddress.Addr[1] = (MacAddrLowValue & 0xFF00) >> 8; + MacAddress.Addr[2] = (MacAddrLowValue & 0xFF0000) >> 16; + MacAddress.Addr[3] = (MacAddrLowValue & 0xFF000000) >> 24; + MacAddress.Addr[4] = (MacAddrHighValue & 0xFF); + MacAddress.Addr[5] = (MacAddrHighValue & 0xFF00) >> 8; + + DEBUG((DEBUG_NET, "GetCurrentMacAddress() = %s\n", Mac2Str (&MacAddress))); + return MacAddress; +} + +#define ReturnUnlock(s) do { Status = (s); goto exit_unlock; } while(0) + +/* +** UEFI Start() function +** +** Parameters: +** +** @param pobj: A pointer to the EFI_SIMPLE_NETWORK_PROTOCOL instance. +** +** Description: +** +** This function starts a network interface. If the network interface successfully starts, then +** EFI_SUCCESS will be returned. +*/ +EFI_STATUS +EFIAPI +SnpStart ( + IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp + ) +{ + EFI_MAC_ADDRESS *Mac; + EFI_TPL SavedTpl; + EFI_STATUS Status; + + // Check Snp instance + if (Snp == NULL) { + return EFI_INVALID_PARAMETER; + } + + // Serialize access to data and registers + SavedTpl = gBS->RaiseTPL (LAN9118_TPL); + + // Check state + if ((Snp->Mode->State == EfiSimpleNetworkStarted) || (Snp->Mode->State == EfiSimpleNetworkInitialized)) { + ReturnUnlock (EFI_ALREADY_STARTED); + } else if (Snp->Mode->State == EfiSimpleNetworkMaxState) { + ReturnUnlock (EFI_DEVICE_ERROR); + } + + // Attempt to wake-up the device if it is in a lower power state + if (((MmioRead32 (LAN9118_PMT_CTRL) & MPTCTRL_PM_MODE_MASK) >> 12) != 0) { + DEBUG((DEBUG_NET, "Waking from reduced power state.\n")); + MmioWrite32 (LAN9118_BYTE_TEST, 0xFFFFFFFF); + gBS->Stall (LAN9118_STALL); + } + + // Check that device is active + while ((MmioRead32 (LAN9118_PMT_CTRL) & MPTCTRL_READY) == 0); + + // Check that EEPROM isn't active + while (MmioRead32 (LAN9118_E2P_CMD) & E2P_EPC_BUSY); + + Mac = &Snp->Mode->CurrentAddress; + DEBUG((DEBUG_NET, "Using current address %s\n", Mac2Str(Mac))); + IndirectMACWrite32 (INDIRECT_MAC_INDEX_ADDRL, + (Mac->Addr[3] << 24) | + (Mac->Addr[2] << 16) | + (Mac->Addr[1] << 8) | + Mac->Addr[0] + ); + + IndirectMACWrite32 (INDIRECT_MAC_INDEX_ADDRH, + (Mac->Addr[5] << 8) | + Mac->Addr[4] + ); + + // Clear and acknowledge interrupts + MmioWrite32 (LAN9118_INT_EN, 0); + MmioWrite32 (LAN9118_IRQ_CFG, 0); + MmioWrite32 (LAN9118_INT_STS, 0xFFFFFFFF); + + // Change state + Snp->Mode->State = EfiSimpleNetworkStarted; + Status = EFI_SUCCESS; + + // Restore TPL and return +exit_unlock: + gBS->RestoreTPL (SavedTpl); + return Status; +} + +/* +** UEFI Stop() function +** +*/ +EFI_STATUS +EFIAPI +SnpStop ( + IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp + ) +{ + EFI_TPL SavedTpl; + EFI_STATUS Status; + + // Check Snp Instance + if (Snp == NULL) { + return EFI_INVALID_PARAMETER; + } + + // Serialize access to data and registers + SavedTpl = gBS->RaiseTPL (LAN9118_TPL); + + // Check state of the driver + if ((Snp->Mode->State == EfiSimpleNetworkStopped) || (Snp->Mode->State == EfiSimpleNetworkMaxState)) { + ReturnUnlock (EFI_NOT_STARTED); + } + + // Stop the Tx and Rx + StopTx (STOP_TX_CFG | STOP_TX_MAC, Snp); + StopRx (0, Snp); + + // Change the state + switch (Snp->Mode->State) { + case EfiSimpleNetworkStarted: + case EfiSimpleNetworkInitialized: + Snp->Mode->State = EfiSimpleNetworkStopped; + break; + default: + ReturnUnlock (EFI_DEVICE_ERROR); + } + Status = EFI_SUCCESS; + + // Restore TPL and return +exit_unlock: + gBS->RestoreTPL (SavedTpl); + return Status; +} + + +// Allocated receive and transmit buffers +STATIC UINT32 gTxBuffer = 0; + +// Buffer sizes +STATIC UINT32 gTxDataSize = 0; +STATIC UINT32 gTxStatusSize = 0; +STATIC UINT32 gRxDataSize = 0; +STATIC UINT32 gRxStatusSize = 0; + +/* +** UEFI Initialize() function +** +*/ +EFI_STATUS +EFIAPI +SnpInitialize ( + IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp, + IN UINTN RxBufferSize OPTIONAL, + IN UINTN TxBufferSize OPTIONAL + ) +{ + EFI_TPL SavedTpl; + EFI_STATUS Status; + UINT32 PmConf; + INT32 AllocResult; + + // Initialize variables + // Global variables to hold tx and rx FIFO allocation + gTxBuffer = 0; + + // Check Snp Instance + if (Snp == NULL) { + return EFI_INVALID_PARAMETER; + } + + // Serialize access to data and registers + SavedTpl = gBS->RaiseTPL (LAN9118_TPL); + + // First check that driver has not already been initialized + if (Snp->Mode->State == EfiSimpleNetworkInitialized) { + DEBUG((EFI_D_WARN, "LAN9118 Driver already initialized\n")); + ReturnUnlock (EFI_SUCCESS); + } else + if (Snp->Mode->State == EfiSimpleNetworkStopped) { + DEBUG((EFI_D_WARN, "LAN9118 Driver not started\n")); + ReturnUnlock (EFI_NOT_STARTED); + } + + // Initiate a PHY reset + if (PhySoftReset (PHY_RESET_PMT | PHY_RESET_CHECK_LINK, Snp) < 0) { + Snp->Mode->State = EfiSimpleNetworkStopped; + DEBUG((EFI_D_WARN, "Warning: Link not ready after TimeOut. Check ethernet cable\n")); + ReturnUnlock (EFI_NOT_STARTED); + } + + // Initiate a software reset + Status = SoftReset (0, Snp); + if (EFI_ERROR(Status)) { + DEBUG((EFI_D_WARN, "Soft Reset Failed: Hardware Error\n")); + ReturnUnlock (EFI_DEVICE_ERROR); + } + + // Read the PM register + PmConf = MmioRead32 (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 + // MPTCTRL_PME_EN: Allow Power Management Events + PmConf = 0; + 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); + + // Configure GPIO and HW + Status = ConfigureHardware (HW_CONF_USE_LEDS, Snp); + if (EFI_ERROR(Status)) { + ReturnUnlock (Status); + } + + // Assign the transmitter buffer size (default values) + gTxDataSize = 4608; + gTxStatusSize = 512; // this never changes + gRxDataSize = 10560; + gRxStatusSize = 704; + + // Check that a buff size was specified + if (TxBufferSize) { + AllocResult = ChangeFifoAllocation ( + ALLOC_USE_FIFOS, + &TxBufferSize, + &RxBufferSize, + &gTxStatusSize, + &gRxStatusSize, + Snp + ); + + if (AllocResult < 0) { + return EFI_OUT_OF_RESOURCES; + } + + gTxDataSize = gTxDataSize; + gTxStatusSize = gTxStatusSize; + gTxDataSize = TxBufferSize; + gRxDataSize = RxBufferSize; + } + + // Set the current MAC Address + Snp->Mode->CurrentAddress = GetCurrentMacAddress (); + + // Set the permanent MAC Address + Snp->Mode->PermanentAddress = Snp->Mode->CurrentAddress; + + // Do auto-negotiation if supported + Status = AutoNegotiate (Snp); + if (EFI_ERROR(Status)) { + DEBUG((EFI_D_WARN, "Lan9118: Auto Negotiation not supported.\n")); + } + + // Configure flow control depending on speed capabilities + Status = ConfigureFlow (0, 0, 0, 0, Snp); + if (EFI_ERROR(Status)) { + ReturnUnlock (Status); + } + + // Enable the receiver and transmitter + Status = StartRx (0, Snp); + if (EFI_ERROR(Status)) { + ReturnUnlock (Status); + } + + Status = StartTx (Snp); + if (EFI_ERROR(Status)) { + ReturnUnlock (Status); + } + + // Now acknowledge all interrupts + MmioWrite32 (LAN9118_INT_STS, 0xFFFFFFFF); + + // Declare the driver as initialized + Snp->Mode->State = EfiSimpleNetworkInitialized; + + // Restore TPL and return +exit_unlock: + gBS->RestoreTPL (SavedTpl); + return Status; +} + +/* +** UEFI Reset () function +** +*/ +EFI_STATUS +EFIAPI +SnpReset ( + IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp, + IN BOOLEAN Verification + ) +{ + EFI_TPL SavedTpl; + EFI_STATUS Status; + UINT32 PmConf; + UINT32 HwConf; + UINT32 ResetFlags; + + PmConf = 0; + HwConf = 0; + ResetFlags = 0; + + // Check Snp Instance + if (Snp == NULL) { + return EFI_INVALID_PARAMETER; + } + + // Serialize access to data and registers + SavedTpl = gBS->RaiseTPL (LAN9118_TPL); + + // First check that driver has not already been initialized + if (Snp->Mode->State == EfiSimpleNetworkStarted) { + DEBUG((EFI_D_WARN, "Warning: LAN9118 Driver not yet initialized\n")); + ReturnUnlock (EFI_DEVICE_ERROR); + } else if (Snp->Mode->State == EfiSimpleNetworkStopped) { + DEBUG((EFI_D_WARN, "Warning: LAN9118 Driver not started\n")); + ReturnUnlock (EFI_NOT_STARTED); + } + + // Initiate a PHY reset + if (PhySoftReset (PHY_RESET_PMT | PHY_RESET_CHECK_LINK, Snp) < 0) { + Snp->Mode->State = EfiSimpleNetworkStopped; + ReturnUnlock (EFI_NOT_STARTED); + } + + // Initiate a software reset + ResetFlags |= SOFT_RESET_CHECK_MAC_ADDR_LOAD | SOFT_RESET_CLEAR_INT; + + if (Verification) { + ResetFlags |= SOFT_RESET_SELF_TEST; + } + + if (SoftReset (ResetFlags, Snp) < 0) { + DEBUG((EFI_D_WARN, "Warning: Soft Reset Failed: Hardware Error\n")); + ReturnUnlock (EFI_DEVICE_ERROR); + } + + // Read the PM register + PmConf = MmioRead32 (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 + // MPTCTRL_PME_EN: Allow Power Management Events + 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); + + // Check that a buffer size was specified in SnpInitialize + if (gTxBuffer != 0) { + HwConf = MmioRead32 (LAN9118_HW_CFG); // Read the HW register + HwConf &= ~((UINT32)0xF0000); // Clear buffer bits first + HwConf |= (gTxBuffer << 16); // assign size chosen in SnpInitialize + + MmioWrite32 (LAN9118_HW_CFG, HwConf); // Write the conf + gBS->Stall (LAN9118_STALL); + } + + // Enable the receiver and transmitter and clear their contents + StartRx (START_RX_CLEAR, Snp); + StartTx (Snp); + + // Now acknowledge all interrupts + MmioWrite32 (LAN9118_INT_STS, 0xFFFFFFFF); + Status = EFI_SUCCESS; + + // Restore TPL and return +exit_unlock: + gBS->RestoreTPL (SavedTpl); + return Status; +} + +/* +** UEFI Shutdown () function +** +*/ +EFI_STATUS +EFIAPI +SnpShutdown ( + IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp + ) +{ + EFI_TPL SavedTpl; + EFI_STATUS Status; + + // Check Snp Instance + if (Snp == NULL) { + return EFI_INVALID_PARAMETER; + } + + // Serialize access to data and registers + SavedTpl = gBS->RaiseTPL (LAN9118_TPL); + + // First check that driver has not already been initialized + if (Snp->Mode->State == EfiSimpleNetworkStarted) { + DEBUG((EFI_D_WARN, "Warning: LAN9118 Driver not yet initialized\n")); + ReturnUnlock (EFI_DEVICE_ERROR); + } else if (Snp->Mode->State == EfiSimpleNetworkStopped) { + DEBUG((EFI_D_WARN, "Warning: LAN9118 Driver in stopped state\n")); + ReturnUnlock (EFI_NOT_STARTED); + } + + // Initiate a PHY reset + PhySoftReset (PHY_RESET_PMT, Snp); + + // Initiate a software reset + if (SoftReset (0, Snp) < 0) { + DEBUG((EFI_D_WARN, "Warning: Soft Reset Failed: Hardware Error\n")); + ReturnUnlock (EFI_DEVICE_ERROR); + } + Status = EFI_SUCCESS; + + // Restore TPL and return +exit_unlock: + gBS->RestoreTPL (SavedTpl); + return Status; +} + + +/* +** 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 + ) +{ + EFI_TPL SavedTpl; + EFI_STATUS Status; + UINT32 MacCSRValue; + UINT32 MultHashTableHigh; + UINT32 MultHashTableLow; + UINT32 Crc; + UINT8 BitToSelect; + UINT32 Count; + + MacCSRValue = 0; + MultHashTableHigh = 0; + MultHashTableLow = 0; + Crc = 0xFFFFFFFF; + BitToSelect = 0; + Count = 0; + + // Serialize access to data and registers + SavedTpl = gBS->RaiseTPL (LAN9118_TPL); + + // Check that driver was started and initialised + if (Snp->Mode->State == EfiSimpleNetworkStarted) { + DEBUG((EFI_D_WARN, "Warning: LAN9118 Driver not initialized\n")); + ReturnUnlock (EFI_DEVICE_ERROR); + } else if (Snp->Mode->State == EfiSimpleNetworkStopped) { + DEBUG((EFI_D_WARN, "Warning: LAN9118 Driver in stopped state\n")); + ReturnUnlock (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); + } + + // Set the hash tables + if ((NumMfilter > 0) && (!Reset)) { + + // Read the Multicast High Hash Table + MultHashTableHigh = IndirectMACRead32 (INDIRECT_MAC_INDEX_HASHH); + + // Read the Multicast Low Hash Table + MultHashTableLow = IndirectMACRead32 (INDIRECT_MAC_INDEX_HASHL); + + // Go through each filter address and set appropriate bits on hash table + for (Count = 0; Count < NumMfilter; Count++) { + + // Generate a 32-bit CRC for Ethernet + Crc = GenEtherCrc32 (&Mfilter[Count],6); + //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; + + // Select hashlow register if MSB is not set + if ((BitToSelect & 0x20) == 0) { + MultHashTableLow |= (1 << BitToSelect); + } else { + MultHashTableHigh |= (1 << (BitToSelect & 0x1F)); + } + } + + // Write the desired hash + IndirectMACWrite32 (INDIRECT_MAC_INDEX_HASHL, MultHashTableLow); + IndirectMACWrite32 (INDIRECT_MAC_INDEX_HASHH, MultHashTableHigh); + } + + // Read MAC controller + MacCSRValue = IndirectMACRead32 (INDIRECT_MAC_INDEX_CR); + + // Set the options for the MAC_CSR + if (Enable & EFI_SIMPLE_NETWORK_RECEIVE_UNICAST) { + StartRx (0, Snp); + DEBUG((DEBUG_NET, "Allowing Unicast Frame Reception\n")); + } + + 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) { + 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 (Disable & EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST) { + MacCSRValue |= MACCR_BCAST; + DEBUG((DEBUG_NET, "Disabling Broadcast Frame Reception\n")); + } + + if (Enable & 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); + Status = EFI_SUCCESS; + + // Restore TPL and return +exit_unlock: + gBS->RestoreTPL (SavedTpl); + return Status; +} + +/* +** UEFI StationAddress() function +** +*/ +EFI_STATUS +EFIAPI +SnpStationAddress ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *Snp, + IN BOOLEAN Reset, + IN EFI_MAC_ADDRESS *NewMac +) +{ + DEBUG((DEBUG_NET, "SnpStationAddress(%d, %s)\n", Reset, Mac2Str(NewMac))); + + EFI_TPL SavedTpl; + EFI_STATUS Status; + UINT32 Count; + UINT8 PermAddr[6]; + + Count = 0; + + // Check Snp instance + if (Snp == NULL) { + return EFI_INVALID_PARAMETER; + } + + // Serialize access to data and registers + SavedTpl = gBS->RaiseTPL (LAN9118_TPL); + + // Check that driver was started and initialised + if (Snp->Mode->State == EfiSimpleNetworkStarted) { + DEBUG((EFI_D_WARN, "Warning: LAN9118 Driver not initialized\n")); + ReturnUnlock (EFI_DEVICE_ERROR); + } else if (Snp->Mode->State == EfiSimpleNetworkStopped) { + DEBUG((EFI_D_WARN, "Warning: LAN9118 Driver in stopped state\n")); + ReturnUnlock (EFI_NOT_STARTED); + } + + // Get the Permanent MAC address if need reset + if (Reset) { + // Try using EEPROM first + if ((IndirectEEPROMRead32 (0) & 0xFF) == 0xA5) { + for (Count = 1; Count < 7; Count++) { + PermAddr[Count - 1] = IndirectEEPROMRead32 (Count); + } + + // Write address + IndirectMACWrite32 (INDIRECT_MAC_INDEX_ADDRL, (UINT32)((UINT32)PermAddr[0]) | ((UINT32)PermAddr[1] << 8) | ((UINT32)PermAddr[2] << 16) | ((UINT32)PermAddr[3] << 24)); + IndirectMACWrite32 (INDIRECT_MAC_INDEX_ADDRH, (UINT32)((((UINT32)PermAddr[4]) | ((UINT32)PermAddr[5] << 8)) & 0xFFFF)); + } else { + // Otherwise make our own + DEBUG((EFI_D_WARN, "Warning: No valid EEPROM detected. Using a hard coded address.\n")); + + IndirectMACWrite32 (INDIRECT_MAC_INDEX_ADDRL, LAN9118_DEFAULT_MAC_ADDRL); + IndirectMACWrite32 (INDIRECT_MAC_INDEX_ADDRH, LAN9118_DEFAULT_MAC_ADDRH); + } + + // Otherwise use the specified new MAC address + } else { + if (NewMac == NULL) { + ReturnUnlock (EFI_INVALID_PARAMETER); + } + + // Write address + IndirectMACWrite32 (INDIRECT_MAC_INDEX_ADDRL, (UINT32)((UINT32)NewMac->Addr[0]) | ((UINT32)NewMac->Addr[1] << 8) | ((UINT32)NewMac->Addr[2] << 16) | ((UINT32)NewMac->Addr[3] << 24)); + IndirectMACWrite32 (INDIRECT_MAC_INDEX_ADDRH, (UINT32)((((UINT32)NewMac->Addr[4]) | ((UINT32)NewMac->Addr[5] << 8)) & 0xFFFF)); + } + + // Restore TPL and return +exit_unlock: + gBS->RestoreTPL (SavedTpl); + return Status; +} + +/* +** UEFI Statistics() function +** +*/ +EFI_STATUS +EFIAPI +SnpStatistics ( + IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp, + IN BOOLEAN Reset, + IN OUT UINTN *StatSize, + OUT EFI_NETWORK_STATISTICS *Statistics + ) +{ + LAN9118_DRIVER *LanDriver; + EFI_TPL SavedTpl; + EFI_STATUS Status; + + DEBUG((DEBUG_NET, "SnpStatistics()\n")); + + // Check Snp instance + if (Snp == NULL) { + return EFI_INVALID_PARAMETER; + } + + // Check pointless condition + if ((!Reset) && (StatSize == NULL) && (Statistics == NULL)) { + return EFI_SUCCESS; + } + + // Check the parameters + if ((StatSize == NULL) && (Statistics != NULL)) { + return EFI_INVALID_PARAMETER; + } + + // Serialize access to data and registers + SavedTpl = gBS->RaiseTPL (LAN9118_TPL); + + // Check that driver was started and initialised + if (Snp->Mode->State == EfiSimpleNetworkStarted) { + DEBUG((EFI_D_WARN, "Warning: LAN9118 Driver not initialized\n")); + ReturnUnlock (EFI_DEVICE_ERROR); + } else if (Snp->Mode->State == EfiSimpleNetworkStopped) { + DEBUG((EFI_D_WARN, "Warning: LAN9118 Driver in stopped state\n")); + ReturnUnlock (EFI_NOT_STARTED); + } + + // Do a reset if required + if (Reset) { + ZeroMem (&LanDriver->Stats, sizeof(EFI_NETWORK_STATISTICS)); + } + + // Check buffer size + if (*StatSize < sizeof(EFI_NETWORK_STATISTICS)) { + *StatSize = sizeof(EFI_NETWORK_STATISTICS); + ReturnUnlock (EFI_BUFFER_TOO_SMALL); + } + + // Fill in the statistics + CopyMem(&Statistics, &LanDriver->Stats, sizeof(EFI_NETWORK_STATISTICS)); + Status = EFI_SUCCESS; + + // Restore TPL and return +exit_unlock: + gBS->RestoreTPL (SavedTpl); + return Status; +} + +/* +** UEFI MCastIPtoMAC() function +** +*/ +EFI_STATUS +EFIAPI +SnpMcastIptoMac ( + IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp, + IN BOOLEAN IsIpv6, + IN EFI_IP_ADDRESS *Ip, + OUT EFI_MAC_ADDRESS *McastMac + ) +{ + DEBUG((DEBUG_NET, "SnpMcastIptoMac()\n")); + + // Check Snp instance + if (Snp == NULL) { + return EFI_INVALID_PARAMETER; + } + + // Check parameters + if ((McastMac == NULL) || (Ip == NULL)) { + return EFI_INVALID_PARAMETER; + } + + // Make sure MAC address is empty + ZeroMem (McastMac, sizeof(EFI_MAC_ADDRESS)); + + // If we need ipv4 address + if (!IsIpv6) { + // Most significant 25 bits of a multicast HW address are set + McastMac->Addr[0] = 0x01; + McastMac->Addr[1] = 0x00; + McastMac->Addr[2] = 0x5E; + + // Lower 23 bits from ipv4 address + McastMac->Addr[3] = (Ip->v4.Addr[1] & 0x7F); // Clear the ms bit (25th bit of MAC must be 0) + McastMac->Addr[4] = Ip->v4.Addr[2]; + McastMac->Addr[5] = Ip->v4.Addr[3]; + } else { + // Most significant 16 bits of multicast v6 HW address are set + McastMac->Addr[0] = 0x33; + McastMac->Addr[1] = 0x33; + + // lower four octets are taken from ipv6 address + McastMac->Addr[2] = Ip->v6.Addr[8]; + McastMac->Addr[3] = Ip->v6.Addr[9]; + McastMac->Addr[4] = Ip->v6.Addr[10]; + McastMac->Addr[5] = Ip->v6.Addr[11]; + } + + return EFI_SUCCESS; +} + +/* +** UEFI NvData() function +** +*/ +EFI_STATUS +EFIAPI +SnpNvData ( + IN EFI_SIMPLE_NETWORK_PROTOCOL* pobj, + IN BOOLEAN read_write, + IN UINTN offset, + IN UINTN buff_size, + IN OUT VOID *data + ) +{ + DEBUG((DEBUG_NET, "SnpNvData()\n")); + + return EFI_UNSUPPORTED; +} + + +/* +** UEFI GetStatus () function +** +*/ +EFI_STATUS +EFIAPI +SnpGetStatus ( + IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp, + OUT UINT32 *IrqStat OPTIONAL, + OUT VOID **TxBuff OPTIONAL + ) +{ + LAN9118_DRIVER *LanDriver; + EFI_STATUS Status; + EFI_TPL SavedTpl; + UINT32 FifoInt; + UINT32 IntStatus; + BOOLEAN MediaPresent; + UINT32 TxStatus; + INTN TxCacheIndex; + + // Check preliminaries + if (Snp == NULL) { + return EFI_INVALID_PARAMETER; + } + + // Serialize access to data and registers + SavedTpl = gBS->RaiseTPL (LAN9118_TPL); + + if (Snp->Mode->State != EfiSimpleNetworkInitialized) { + ReturnUnlock (EFI_NOT_STARTED); + } + + LanDriver = INSTANCE_FROM_SNP_THIS(Snp); + + // Set the transmit status available level + FifoInt = MmioRead32 (LAN9118_FIFO_INT); + + if ((FifoInt & 0x00FF0000) == 0) { + FifoInt |= (1 << 16); + MmioWrite32 (LAN9118_FIFO_INT, FifoInt); + } + + IntStatus = MmioRead32 (LAN9118_INT_STS); + if ((IntStatus & (INSTS_TXSTOP_INT | INSTS_RXSTOP_INT | INSTS_TXSO | INSTS_RWT | + INSTS_RXE | INSTS_TXE | INSTS_TDFO | INSTS_TDFA | INSTS_TSFF | + INSTS_TSFL | INSTS_RXDF_INT | INSTS_RSFF)) != 0) { + DEBUG((EFI_D_WARN, "IntStatus: %08x\n", IntStatus)); + } + + // Report interrupt status if IrqStat is not NULL + if (IrqStat != NULL) { + *IrqStat = 0; + + // Check for receive interrupt + if (IntStatus & INSTS_RSFL) { // Data moved from rx FIFO + *IrqStat |= EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT; + MmioWrite32 (LAN9118_INT_STS,INSTS_RSFL); + } + + // Check for transmit interrupt + if (IntStatus & INSTS_TSFL) { + *IrqStat |= EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT; + MmioWrite32 (LAN9118_INT_STS,INSTS_TSFL); + } + + // Check for software interrupt + if (IntStatus & INSTS_SW_INT) { + *IrqStat |= EFI_SIMPLE_NETWORK_SOFTWARE_INTERRUPT; + MmioWrite32 (LAN9118_INT_STS,INSTS_SW_INT); + } + } + + // Return the recycled transmit address + if ((TxBuff != NULL) && (TxStatusUsedSpace (Snp) > 0)) { + TxStatus = MmioRead32 (LAN9118_TX_STATUS); + + TxCacheIndex = ((INTN)(TxStatus >> 16) & 0xffff) - 1; + if ((0 <= TxCacheIndex) && (TxCacheIndex < LAN9118_TX_CACHE_DEPTH)) { + if (LanDriver->TxCache[TxCacheIndex] != NULL) { + *TxBuff = LanDriver->TxCache[TxCacheIndex]; + LanDriver->TxCache[TxCacheIndex] = NULL; + } else { + *TxBuff = NULL; + } + } else { + *TxBuff = NULL; + } + + // Check Tx Status (we ignore TXSTATUS_NO_CA has it might happen in Full Duplex) + if (((TxStatus & TXSTATUS_ES) != 0) && ((TxStatus & TXSTATUS_NO_CA) == 0)) { + DEBUG((EFI_D_WARN, "Warning: There was an error transmitting TxStatus=0x%X:\n", TxStatus)); + if (TxStatus & TXSTATUS_DEF) { + DEBUG((EFI_D_WARN, "- Packet tx was deferred\n")); + } + if (TxStatus & TXSTATUS_EDEF) { + DEBUG((EFI_D_WARN, "- Tx ended because of excessive deferral\n")); + } + if (TxStatus & TXSTATUS_ECOLL) { + DEBUG((EFI_D_WARN, "- Tx ended because of Excessive Collisions\n")); + } + if (TxStatus & TXSTATUS_LCOLL) { + DEBUG((EFI_D_WARN, "- Packet Tx aborted after coll window of 64 bytes\n")); + } + if (TxStatus & TXSTATUS_LOST_CA) { + DEBUG((EFI_D_WARN, "- Lost carrier during Tx\n")); + } + } + } + + // Update the media status + MediaPresent = CheckLinkStatus (Snp); + if (MediaPresent != Snp->Mode->MediaPresent) { + DEBUG((EFI_D_WARN, "LAN9118: Link %s\n", MediaPresent ? L"up" : L"down")); + } + Snp->Mode->MediaPresent = MediaPresent; + Status = EFI_SUCCESS; + + // Restore TPL and return +exit_unlock: + gBS->RestoreTPL (SavedTpl); + return Status; +} + + +/* +** UEFI Transmit() function +** +*/ +EFI_STATUS +EFIAPI +SnpTransmit ( + IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp, + IN UINTN HdrSize, + IN UINTN BuffSize, + IN VOID *Data, + IN EFI_MAC_ADDRESS *SrcAddr OPTIONAL, + IN EFI_MAC_ADDRESS *DstAddr OPTIONAL, + IN UINT16 *Protocol OPTIONAL + ) +{ + LAN9118_DRIVER *LanDriver; + EFI_TPL SavedTpl; + EFI_STATUS Status; + UINT32 TxFreeSpace; + UINT32 TxStatusSpace; + INT32 Count; + UINT32 CommandA; + UINT32 CommandB; + UINT16 LocalProtocol; + UINT32 *LocalData; + INTN TxCacheIndex; + + // Check preliminaries + if ((Snp == NULL) || (Data == NULL)) { + return EFI_INVALID_PARAMETER; + } + + // Serialize access to data and registers + SavedTpl = gBS->RaiseTPL (LAN9118_TPL); + + if (Snp->Mode->State != EfiSimpleNetworkInitialized) { + ReturnUnlock (EFI_NOT_STARTED); + } + + // Ensure header is correct size if non-zero + if (HdrSize) { + if (HdrSize != Snp->Mode->MediaHeaderSize) { + ReturnUnlock (EFI_INVALID_PARAMETER); + } + + if ((DstAddr == NULL) || (Protocol == NULL)) { + ReturnUnlock (EFI_INVALID_PARAMETER); + } + } + + // Before transmitting check the link status + if (!Snp->Mode->MediaPresent) { + ReturnUnlock (EFI_NOT_READY); + } + + LanDriver = INSTANCE_FROM_SNP_THIS(Snp); + TxCacheIndex = (-1); + + // Find a free entry in the TxCache array + for (TxCacheIndex = LAN9118_TX_CACHE_DEPTH - 1; TxCacheIndex >= 0; --TxCacheIndex) { + if (LanDriver->TxCache[TxCacheIndex] == NULL) { + break; + } + } + if (TxCacheIndex < 0) { + ReturnUnlock (EFI_NOT_READY); + } + LanDriver->TxCache[TxCacheIndex] = Data; + + // Get DATA FIFO free space in bytes + TxFreeSpace = TxDataFreeSpace (Snp); + if (TxFreeSpace < BuffSize) { + ReturnUnlock (EFI_NOT_READY); + } + + // Get STATUS FIFO used space in DWORDS + TxStatusSpace = TxStatusUsedSpace (Snp); + if (TxStatusSpace > 125) { + ReturnUnlock (EFI_NOT_READY); + } + + // Check for the nature of the frame + if ((DstAddr->Addr[0] & 0x1) == 1) { + LanDriver->Stats.TxMulticastFrames += 1; + } else { + LanDriver->Stats.TxUnicastFrames += 1; + } + + // Check if broadcast + if (DstAddr->Addr[0] == 0xFF) { + LanDriver->Stats.TxBroadcastFrames += 1; + } + + if (HdrSize) { + // Format pointer + LocalData = (UINT32*) Data; + LocalProtocol = *Protocol; + + // Create first buffer to pass to controller (for the header) + CommandA = TX_CMD_A_FIRST_SEGMENT | TX_CMD_A_BUFF_SIZE(HdrSize); + CommandB = TX_CMD_B_PACKET_TAG(TxCacheIndex + 1) | TX_CMD_B_PACKET_LENGTH(BuffSize); + + // Write the commands first + MmioWrite32 (LAN9118_TX_DATA, CommandA); + MmioWrite32 (LAN9118_TX_DATA, CommandB); + + // Write the destination address + MmioWrite32 (LAN9118_TX_DATA, + (DstAddr->Addr[0]) | + (DstAddr->Addr[1] << 8) | + (DstAddr->Addr[2] << 16) | + (DstAddr->Addr[3] << 24) + ); + + MmioWrite32 (LAN9118_TX_DATA, + (DstAddr->Addr[4]) | + (DstAddr->Addr[5] << 8) | + + // Write the Source Address + (SrcAddr->Addr[0] << 16) | + (SrcAddr->Addr[1] << 24) + ); + + MmioWrite32 (LAN9118_TX_DATA, + (SrcAddr->Addr[2]) | + (SrcAddr->Addr[3] << 8) | + (SrcAddr->Addr[4] << 16) | + (SrcAddr->Addr[5] << 24) + ); + + // Write the Protocol + MmioWrite32 (LAN9118_TX_DATA, (UINT32)(HTONS(LocalProtocol))); + + // Next buffer is the payload + CommandA = TX_CMD_A_COMPLETION_INT | TX_CMD_A_START_OFFSET(2) | + TX_CMD_A_LAST_SEGMENT | TX_CMD_A_BUFF_SIZE(BuffSize - HdrSize); + + // Write the commands + MmioWrite32 (LAN9118_TX_DATA, CommandA); + MmioWrite32 (LAN9118_TX_DATA, CommandB); + + // Write the payload + for (Count = 0; Count < ((BuffSize + 3) >> 2) - 3; Count++) { + MmioWrite32 (LAN9118_TX_DATA,LocalData[Count + 3]); + } + + // Get STATUS FIFO used space in bytes + /*TxStatusSpace = TxStatusUsedSpace (0, Snp); + DEBUG((EFI_D_ERROR, "Status FIFO Size after write: %d\n",TxStatusSpace)); + + // Data written debug + DEBUG((EFI_D_ERROR, "Payload written: %d bytes",BuffSize - HdrSize)); + for (Count = 0; Count < ((BuffSize + 3) >> 2) - 3; Count++) { + if ((Count % 6) == 0) + DEBUG((EFI_D_ERROR, "\n")); + DEBUG((DEBUG_NET, "0x%08X", NTOHL(LocalData[Count + 3]))); + } + DEBUG((EFI_D_ERROR, "\n")); + */ + + } else { + + // Format pointer + LocalData = (UINT32*) Data; + + // Create a buffer to pass to controller + CommandA = TX_CMD_A_COMPLETION_INT | TX_CMD_A_FIRST_SEGMENT | + TX_CMD_A_LAST_SEGMENT | TX_CMD_A_BUFF_SIZE(BuffSize); + CommandB = TX_CMD_B_PACKET_TAG(TxCacheIndex + 1) | TX_CMD_B_PACKET_LENGTH(BuffSize); + + // Write the commands first + MmioWrite32 (LAN9118_TX_DATA, CommandA); + MmioWrite32 (LAN9118_TX_DATA, CommandB); + + // Write all the data + for (Count = 0; Count < ((BuffSize + 3) >> 2); Count++) { + MmioWrite32 (LAN9118_TX_DATA,LocalData[Count]); + } + + // Data written debug + /*DEBUG((EFI_D_ERROR, "Packet written:")); + for (Count = 0; Count < ((BuffSize + 3) >> 2); Count++) { + if ((Count % 6) == 0) + DEBUG((EFI_D_ERROR, "\n")); + DEBUG((DEBUG_NET, "0x%08X",LocalData[Count])); + }*/ + } + + LanDriver->Stats.TxTotalFrames += 1; + LanDriver->Stats.TxGoodFrames += 1; + TxCacheIndex = (-1); + Status = EFI_SUCCESS; + + // Restore TPL and return +exit_unlock: + if (TxCacheIndex >= 0) { + LanDriver->TxCache[TxCacheIndex] = NULL; + } + gBS->RestoreTPL (SavedTpl); + return Status; +} + + +/* +** UEFI Receive() function +** +*/ +EFI_STATUS +EFIAPI +SnpReceive ( + IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp, + OUT UINTN *HdrSize OPTIONAL, + IN OUT UINTN *BuffSize, + OUT VOID *Data, + OUT EFI_MAC_ADDRESS *SrcAddr OPTIONAL, + OUT EFI_MAC_ADDRESS *DstAddr OPTIONAL, + OUT UINT16 *Protocol OPTIONAL + ) +{ + EFI_TPL SavedTpl; + EFI_STATUS Status; + LAN9118_DRIVER *LanDriver; + UINT32 RxFifoStatus; + UINT32 NumPackets; + UINT32 RxDataUsed; + UINT32 RxStatusUsed; + UINT32 RxCfgValue; + UINT32 PLength; // Packet length + UINT32 ReadLimit; + UINT32 Count; + UINT32 Padding; + UINT32 *RawData; + EFI_MAC_ADDRESS Dst; + EFI_MAC_ADDRESS Src; + + // Check preliminaries + if ((Snp == NULL) || (Data == NULL)) { + return EFI_INVALID_PARAMETER; + } + + // Serialize access to data and registers + SavedTpl = gBS->RaiseTPL (LAN9118_TPL); + + // Check state + if (Snp->Mode->State != EfiSimpleNetworkInitialized) { + ReturnUnlock (EFI_NOT_STARTED); + } + + LanDriver = INSTANCE_FROM_SNP_THIS(Snp); + + // Before receiving check the link status + /*if (CheckLinkStatus (Snp) < 0) { + ReturnUnlock (EFI_NOT_READY); + }*/ + + // Get the used space in rx fifo + RxDataUsed = RxDataUsedSpace (0, Snp); + if (RxDataUsed > gRxDataSize - 4) { + LanDriver->Stats.RxDroppedFrames += 1; + ReturnUnlock (EFI_NOT_READY); + } + + // Get the used status space + RxStatusUsed = RxStatusUsedSpace (0, Snp); + if (RxStatusUsed > gRxStatusSize - 4) { + LanDriver->Stats.RxDroppedFrames += 1; + ReturnUnlock (EFI_NOT_READY); + } + + // Get the number of packets to read + NumPackets = RxStatusUsed >> 2; + if (!NumPackets) { + ReturnUnlock (EFI_NOT_READY); + } + + // Read Rx Status (only if not empty) + RxFifoStatus = MmioRead32 (LAN9118_RX_STATUS); + LanDriver->Stats.RxTotalFrames += 1; + + // First check for errors + if ((RxFifoStatus & RXSTATUS_MII_ERROR) || + (RxFifoStatus & RXSTATUS_RXW_TO) || + (RxFifoStatus & RXSTATUS_FTL) || + (RxFifoStatus & RXSTATUS_LCOLL) || + (RxFifoStatus & RXSTATUS_LE) || + (RxFifoStatus & RXSTATUS_DB)) + { + DEBUG((EFI_D_WARN, "Warning: There was an error on frame reception.\n")); + ReturnUnlock (EFI_DEVICE_ERROR); + } + + // Check if we got a CRC error + if (RxFifoStatus & RXSTATUS_CRC_ERROR) { + DEBUG((EFI_D_WARN, "Warning: Crc Error\n")); + LanDriver->Stats.RxCrcErrorFrames += 1; + LanDriver->Stats.RxDroppedFrames += 1; + ReturnUnlock (EFI_DEVICE_ERROR); + } + + // Check if we got a runt frame + if (RxFifoStatus & RXSTATUS_RUNT) { + DEBUG((EFI_D_WARN, "Warning: Runt Frame\n")); + LanDriver->Stats.RxUndersizeFrames += 1; + LanDriver->Stats.RxDroppedFrames += 1; + ReturnUnlock (EFI_DEVICE_ERROR); + } + + // Check filtering status for this packet + if (RxFifoStatus & RXSTATUS_FILT_FAIL) { + DEBUG((EFI_D_WARN, "Warning: Frame Failed Filtering\n")); + // fast forward? + } + + // Check if we got a broadcast frame + if (RxFifoStatus & RXSTATUS_BCF) { + LanDriver->Stats.RxBroadcastFrames += 1; + } + + // Check if we got a multicast frame + if (RxFifoStatus & RXSTATUS_MCF) { + LanDriver->Stats.RxMulticastFrames += 1; + } + + // Check if we got a unicast frame + if ((RxFifoStatus & RXSTATUS_BCF) && ((RxFifoStatus & RXSTATUS_MCF) == 0)) { + LanDriver->Stats.RxUnicastFrames += 1; + } + + // Get the received packet length + PLength = (RxFifoStatus & RXSTATUS_PL_MASK) >> 16; + LanDriver->Stats.RxTotalBytes += (PLength - 4); + + // Check buffer size + if (*BuffSize < PLength) { + *BuffSize = PLength; + ReturnUnlock (EFI_BUFFER_TOO_SMALL); + } + + // If padding is applied, read more DWORDs + if (PLength % 4) { + Padding = 4 - (PLength % 4); + ReadLimit = (PLength + Padding)/4; + } else { + ReadLimit = PLength/4; + Padding = 0; + } + + // 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 &= ~(RXCFG_RX_DMA_CNT_MASK); + RxCfgValue |= (ReadLimit & 0xFFFF) << 16; + + // Set end alignment to 4-bytes + RxCfgValue &= ~(RXCFG_RX_END_ALIGN_MASK); + MmioWrite32 (LAN9118_RX_CFG, RxCfgValue); + + // Update buffer size + *BuffSize = PLength; // -4 bytes may be needed: Received in buffer as + // 4 bytes longer than packet actually is, unless + // packet is < 64 bytes + + if (HdrSize != NULL) + *HdrSize = Snp->Mode->MediaHeaderSize; + + // Format the pointer + RawData = (UINT32*)Data; + + // 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")); + ReturnUnlock (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 + ReturnUnlock (EFI_DEVICE_ERROR); + } + + // Get the destination address + if (DstAddr != NULL) { + Dst.Addr[0] = (RawData[0] & 0xFF); + Dst.Addr[1] = (RawData[0] & 0xFF00) >> 8; + Dst.Addr[2] = (RawData[0] & 0xFF0000) >> 16; + Dst.Addr[3] = (RawData[0] & 0xFF000000) >> 24; + Dst.Addr[4] = (RawData[1] & 0xFF); + Dst.Addr[5] = (RawData[1] & 0xFF00) >> 8; + CopyMem (DstAddr, &Dst, NET_ETHER_ADDR_LEN); + } + + // Get the source address + if (SrcAddr != NULL) { + Src.Addr[0] = (RawData[1] & 0xFF0000) >> 16; + Src.Addr[1] = (RawData[1] & 0xFF000000) >> 24; + Src.Addr[2] = (RawData[2] & 0xFF); + 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); + } + + // Get the protocol + if (Protocol != NULL) { + *Protocol = NTOHS (RawData[3] & 0xFFFF); + } + + LanDriver->Stats.RxGoodFrames += 1; + Status = EFI_SUCCESS; + +exit_unlock: + gBS->RestoreTPL (SavedTpl); + return Status; +} + + + +/* +** Entry point for the LAN9118 driver +** +*/ +EFI_STATUS +Lan9118DxeEntry ( + IN EFI_HANDLE Handle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + LAN9118_DRIVER *LanDriver; + EFI_SIMPLE_NETWORK_PROTOCOL *Snp; + EFI_SIMPLE_NETWORK_MODE *SnpMode; + LAN9118_DEVICE_PATH *Lan9118Path; + EFI_HANDLE ControllerHandle; + + // The PcdLan9118DxeBaseAddress PCD must be defined + ASSERT(PcdGet32 (PcdLan9118DxeBaseAddress) != 0); + + // Allocate Resources + LanDriver = AllocateZeroPool (sizeof(LAN9118_DRIVER)); + Lan9118Path = (LAN9118_DEVICE_PATH*)AllocateCopyPool(sizeof(LAN9118_DEVICE_PATH), &Lan9118PathTemplate); + + // Initialize pointers + Snp = &(LanDriver->Snp); + SnpMode = &(LanDriver->SnpMode); + Snp->Mode = SnpMode; + + // Set the signature of the LAN Driver structure + LanDriver->Signature = LAN9118_SIGNATURE; + + // Assign fields and func pointers + Snp->Revision = EFI_SIMPLE_NETWORK_PROTOCOL_REVISION; + Snp->WaitForPacket = NULL; + Snp->Initialize = SnpInitialize; + Snp->Start = SnpStart; + Snp->Stop = SnpStop; + Snp->Reset = SnpReset; + Snp->Shutdown = SnpShutdown; + Snp->ReceiveFilters = SnpReceiveFilters; + Snp->StationAddress = SnpStationAddress; + Snp->Statistics = SnpStatistics; + Snp->MCastIpToMac = SnpMcastIptoMac; + Snp->NvData = SnpNvData; + Snp->GetStatus = SnpGetStatus; + Snp->Transmit = SnpTransmit; + Snp->Receive = SnpReceive; + + // Start completing simple network mode structure + SnpMode->State = EfiSimpleNetworkStopped; + SnpMode->HwAddressSize = NET_ETHER_ADDR_LEN; // HW address is 6 bytes + SnpMode->MediaHeaderSize = sizeof(ETHER_HEAD); // Not sure of this + SnpMode->MaxPacketSize = EFI_PAGE_SIZE; // Preamble + SOF + Ether Frame (with VLAN tag +4bytes) + 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; + + // LAN9118 has 64bit multicast hash table + SnpMode->MaxMCastFilterCount = MAX_MCAST_FILTER_CNT; + SnpMode->MCastFilterCount = 0; + ZeroMem (&SnpMode->MCastFilter, MAX_MCAST_FILTER_CNT * sizeof(EFI_MAC_ADDRESS)); + + // Set the interface type (1: Ethernet or 6: IEEE 802 Networks) + SnpMode->IfType = NET_IFTYPE_ETHERNET; + + // Mac address is changeable as it is loaded from erasable memory + SnpMode->MacAddressChangeable = TRUE; + + // Can only transmit one packet at a time + SnpMode->MultipleTxSupported = FALSE; + + // MediaPresent checks for cable connection and partner link + SnpMode->MediaPresentSupported = TRUE; + SnpMode->MediaPresent = FALSE; + + // Set broadcast address + SetMem (&SnpMode->BroadcastAddress, sizeof (EFI_MAC_ADDRESS), 0xFF); + + // Assign fields for device path + Lan9118Path->Lan9118.MacAddress = GetCurrentMacAddress (); + Lan9118Path->Lan9118.IfType = Snp->Mode->IfType; + + // Initialise the protocol + ControllerHandle = 0; + Status = gBS->InstallMultipleProtocolInterfaces ( + &ControllerHandle, + &gEfiSimpleNetworkProtocolGuid, Snp, + &gEfiDevicePathProtocolGuid, Lan9118Path, + NULL + ); + // Say what the status of loading the protocol structure is + if (EFI_ERROR(Status)) { + FreePool (LanDriver); + } else { + LanDriver->ControllerHandle = ControllerHandle; + } + + return Status; +} diff --git a/ArmPlatformPkg/Drivers/LAN9118Dxe/LAN9118Dxe.inf b/ArmPlatformPkg/Drivers/LAN9118Dxe/LAN9118Dxe.inf new file mode 100644 index 000000000..232f502cc --- /dev/null +++ b/ArmPlatformPkg/Drivers/LAN9118Dxe/LAN9118Dxe.inf @@ -0,0 +1,55 @@ +#/** @file +# INF file for the LAN9118 Network Controller Driver. +# +# Copyright (c) 2012-2013, 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. +# +#**/ + +[Defines] + INF_VERSION = 0x00010006 + BASE_NAME = LAN9118Dxe + FILE_GUID = 4356b162-d0b2-11e1-8952-4437e6a60ea5 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 0.1 + ENTRY_POINT = Lan9118DxeEntry + +[Sources.common] + LAN9118Dxe.c + LAN9118DxeHw.h + +[Packages] + ArmPlatformPkg/ArmPlatformPkg.dec + NetworkPkg/NetworkPkg.dec + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + +[LibraryClasses] + BaseLib + UefiLib + NetLib + UefiDriverEntryPoint + BaseMemoryLib + ArmLib + IoLib + TimerLib + DevicePathLib + +[Protocols] + gEfiSimpleNetworkProtocolGuid + gEfiMetronomeArchProtocolGuid + gEfiPxeBaseCodeProtocolGuid + gEfiDevicePathProtocolGuid + +[FixedPcd] + gArmPlatformTokenSpaceGuid.PcdLan9118DxeBaseAddress + +[Depex] + TRUE diff --git a/ArmPlatformPkg/Drivers/LAN9118Dxe/LAN9118DxeHw.h b/ArmPlatformPkg/Drivers/LAN9118Dxe/LAN9118DxeHw.h new file mode 100644 index 000000000..f622d0b54 --- /dev/null +++ b/ArmPlatformPkg/Drivers/LAN9118Dxe/LAN9118DxeHw.h @@ -0,0 +1,325 @@ +/** @file +* +* Copyright (c) 2012-2013, 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. +* +**/ + +#ifndef __LAN9118_DXE_HW_H__ +#define __LAN9118_DXE_HW_H__ + +/*--------------------------------------------------------------------------------------------------------------------- + + LAN9118 SMCS Registers + +---------------------------------------------------------------------------------------------------------------------*/ + +// Base address as on the VE board +#define LAN9118_BA ((UINT32) PcdGet32(PcdLan9118DxeBaseAddress)) + +/* ------------------------------ Tx and Rx Data and Status Memory Locations -------------------------------- */ +#define LAN9118_RX_DATA (0x00000000 + LAN9118_BA) +#define LAN9118_RX_STATUS (0x00000040 + LAN9118_BA) +#define LAN9118_RX_STATUS_PEEK (0x00000044 + LAN9118_BA) +#define LAN9118_TX_DATA (0x00000020 + LAN9118_BA) +#define LAN9118_TX_STATUS (0x00000048 + LAN9118_BA) +#define LAN9118_TX_STATUS_PEEK (0x0000004C + LAN9118_BA) + +/* ---------------------------------- System Control and Status Registers ----------------------------------- */ +#define LAN9118_ID_REV (0x00000050 + LAN9118_BA) // Chip ID and Revision +#define LAN9118_IRQ_CFG (0x00000054 + LAN9118_BA) // Interrupt Configuration +#define LAN9118_INT_STS (0x00000058 + LAN9118_BA) // Interrupt Status +#define LAN9118_INT_EN (0x0000005C + LAN9118_BA) // Interrupt Enable +//#define LAN9118_RESERVED (0x00000060) +#define LAN9118_BYTE_TEST (0x00000064 + LAN9118_BA) // Byte Order Test +#define LAN9118_FIFO_INT (0x00000068 + LAN9118_BA) // FIFO Level Interrupts +#define LAN9118_RX_CFG (0x0000006C + LAN9118_BA) // Receive Configuration +#define LAN9118_TX_CFG (0x00000070 + LAN9118_BA) // Transmit Configuration +#define LAN9118_HW_CFG (0x00000074 + LAN9118_BA) // Hardware Configuration +#define LAN9118_RX_DP_CTL (0x00000078 + LAN9118_BA) // Receive Data-Path Configuration +#define LAN9118_RX_FIFO_INF (0x0000007C + LAN9118_BA) // Receive FIFO Information +#define LAN9118_TX_FIFO_INF (0x00000080 + LAN9118_BA) // Transmit FIFO Information +#define LAN9118_PMT_CTRL (0x00000084 + LAN9118_BA) // Power Management Control +#define LAN9118_GPIO_CFG (0x00000088 + LAN9118_BA) // General Purpose IO Configuration +#define LAN9118_GPT_CFG (0x0000008C + LAN9118_BA) // General Purpose Timer Configuration +#define LAN9118_GPT_CNT (0x00000090 + LAN9118_BA) // General Purpose Timer Current Count +//#define LAN9118_RESERVED (0x00000094) +#define LAN9118_WORD_SWAP (0x00000098 + LAN9118_BA) // Word Swap Control +#define LAN9118_FREE_RUN (0x0000009C + LAN9118_BA) // Free-Run 25MHz Counter +#define LAN9118_RX_DROP (0x000000A0 + LAN9118_BA) // Receiver Dropped Frames Counter +#define LAN9118_MAC_CSR_CMD (0x000000A4 + LAN9118_BA) // MAC CSR Synchronizer Command +#define LAN9118_MAC_CSR_DATA (0x000000A8 + LAN9118_BA) // MAC CSR Synchronizer Data +#define LAN9118_AFC_CFG (0x000000AC + LAN9118_BA) // Automatic Flow Control Configuration +#define LAN9118_E2P_CMD (0x000000B0 + LAN9118_BA) // EEPROM Command +#define LAN9118_E2P_DATA (0x000000B4 + LAN9118_BA) // EEPROM Data +//#define LAN9118_RESERVED (0x000000B8 - 0x000000FC) + + +// Receiver Status bits +#define RXSTATUS_CRC_ERROR BIT1 // Cyclic Redundancy Check Error +#define RXSTATUS_DB BIT2 // Dribbling bit: Frame had non-integer multiple of 8bits +#define RXSTATUS_MII_ERROR BIT3 // Receive error during interception +#define RXSTATUS_RXW_TO BIT4 // Incomming frame larger than 2kb +#define RXSTATUS_FT BIT5 // 1: Ether type / 0: 802.3 type frame +#define RXSTATUS_LCOLL BIT6 // Late collision detected +#define RXSTATUS_FTL BIT7 // Frame longer than Ether type +#define RXSTATUS_MCF BIT10 // Frame has Multicast Address +#define RXSTATUS_RUNT BIT11 // Bad frame +#define RXSTATUS_LE BIT12 // Actual length of frame different than it claims +#define RXSTATUS_BCF BIT13 // Frame has Broadcast Address +#define RXSTATUS_ES BIT15 // Reports any error from bits 1,6,7 and 11 +#define RXSTATUS_PL_MASK (0x3FFF0000) // Packet length bit mask +#define RXSTATUS_FILT_FAIL BIT30 // The frame failed filtering test + +// Transmitter Status bits +#define TXSTATUS_DEF BIT0 // Packet tx was deferred +#define TXSTATUS_EDEF BIT2 // Tx ended because of excessive deferral (> 24288 bit times) +#define TXSTATUS_CC_MASK (0x00000078) // Collision Count (before Tx) bit mask +#define TXSTATUS_ECOLL BIT8 // Tx ended because of Excessive Collisions (makes CC_MASK invalid after 16 collisions) +#define TXSTATUS_LCOLL BIT9 // Packet Tx aborted after coll window of 64 bytes +#define TXSTATUS_NO_CA BIT10 // Carrier signal not present during Tx (bad?) +#define TXSTATUS_LOST_CA BIT11 // Lost carrier during Tx +#define TXSTATUS_ES BIT15 // Reports any errors from bits 1,2,8,9,10 and 11 +#define TXSTATUS_PTAG_MASK (0xFFFF0000) // Mask for Unique ID of packets (So we know who the packets are for) + +// ID_REV register bits +#define IDREV_ID ((MmioRead32(LAN9118_ID_REV) & 0xFFFF0000) >> 16) +#define IDREV_REV (MmioRead32(LAN9118_ID_REV) & 0x0000FFFF) + +// Interrupt Config Register bits +#define IRQCFG_IRQ_TYPE BIT0 // IRQ Buffer type +#define IRQCFG_IRQ_POL BIT4 // IRQ Polarity +#define IRQCFG_IRQ_EN BIT8 // Enable external interrupt +#define IRQCFG_IRQ_INT BIT12 // State of internal interrupts line +#define IRQCFG_INT_DEAS_STS BIT13 // State of deassertion interval +#define IRQCFG_INT_DEAS_CLR BIT14 // Clear the deassertion counter +#define IRQCFG_INT_DEAS_MASK (0xFF000000) // Interrupt deassertion interval value mask + +// Interrupt Status Register bits +#define INSTS_GPIO_MASK (0x7) // GPIO interrupts mask +#define INSTS_RSFL BIT3 // Rx Status FIFO Level reached +#define INSTS_RSFF BIT4 // Rx Status FIFO full +#define INSTS_RXDF_INT BIT6 // Rx Frame dropped +#define INSTS_TSFL BIT7 // Tx Status FIFO Level reached +#define INSTS_TSFF BIT8 // Tx Status FIFO full +#define INSTS_TDFA BIT9 // Tx Data FIFO Level exceeded +#define INSTS_TDFO BIT10 // Tx Data FIFO full +#define INSTS_TXE BIT13 // Transmitter Error +#define INSTS_RXE BIT14 // Receiver Error +#define INSTS_RWT BIT15 // Packet > 2048 bytes received +#define INSTS_TXSO BIT16 // Tx Status FIFO Overflow +#define INSTS_PME_INT BIT17 // PME Signal detected +#define INSTS_PHY_INT BIT18 // Indicates PHY Interrupt +#define INSTS_GPT_INT BIT19 // GP Timer wrapped past 0xFFFF +#define INSTS_RXD_INT BIT20 // Indicates that amount of data written to RX_CFG was cleared +#define INSTS_TX_IOC BIT21 // Finished loading IOC flagged buffer to Tx FIFO +#define INSTS_RXDFH_INT BIT23 // Rx Dropped frames went past 0x7FFFFFFF +#define INSTS_RXSTOP_INT BIT24 // Rx was stopped +#define INSTS_TXSTOP_INT BIT25 // Tx was stopped +#define INSTS_SW_INT BIT31 // Software Interrupt occurred + +// Interrupt Enable Register bits + + +// Hardware Config Register bits +#define HWCFG_SRST BIT0 // Software Reset bit (SC) +#define HWCFG_SRST_TO (0x2) // Software Reset Timeout bit (RO) +#define HWCFG_BMODE (0x4) // 32/16 bit Mode bit (RO) +#define HWCFG_TX_FIFO_SIZE_MASK (~ (UINT32)0xF0000) // Mask to Clear FIFO Size +#define HWCFG_MBO BIT20 // Must Be One bit + +// Power Management Control Register +#define MPTCTRL_READY BIT0 // Device ready indicator +#define MPTCTRL_PME_EN BIT1 // Enable external PME signals +#define MPTCTRL_PME_POL BIT2 // Set polarity of PME signals +#define MPTCTRL_PME_IND BIT3 // Signal type of PME (refer to Spec) +#define MPTCTRL_WUPS_MASK (0x18) // Wake up status indicator mask +#define MPTCTRL_PME_TYPE BIT6 // PME Buffer type (Open Drain or Push-Pull) +#define MPTCTRL_ED_EN BIT8 // Energy-detect enable +#define MPTCTRL_WOL_EN BIT9 // Enable wake-on-lan +#define MPTCTRL_PHY_RST BIT10 // Reset the PHY +#define MPTCTRL_PM_MODE_MASK (BIT12 | BIT13) // Set the power mode + +// PHY control register bits +#define PHYCR_COLL_TEST BIT7 // Collision test enable +#define PHYCR_DUPLEX_MODE BIT8 // Set Duplex Mode +#define PHYCR_RST_AUTO BIT9 // Restart Auto-Negotiation of Link abilities +#define PHYCR_PD BIT11 // Power-Down switch +#define PHYCR_AUTO_EN BIT12 // Auto-Negotiation Enable +#define PHYCR_SPEED_SEL BIT13 // Link Speed Selection +#define PHYCR_LOOPBK BIT14 // Set loopback mode +#define PHYCR_RESET BIT15 // Do a PHY reset + +// PHY status register bits +#define PHYSTS_EXT_CAP BIT0 // Extended Capabilities Register capability +#define PHYSTS_JABBER BIT1 // Jabber condition detected +#define PHYSTS_LINK_STS BIT2 // Link Status +#define PHYSTS_AUTO_CAP BIT3 // Auto-Negotiation Capability +#define PHYSTS_REMOTE_FAULT BIT4 // Remote fault detected +#define PHYSTS_AUTO_COMP BIT5 // Auto-Negotiation Completed +#define PHYSTS_10BASET_HDPLX BIT11 // 10Mbps Half-Duplex ability +#define PHYSTS_10BASET_FDPLX BIT12 // 10Mbps Full-Duplex ability +#define PHYSTS_100BASETX_HDPLX BIT13 // 100Mbps Half-Duplex ability +#define PHYSTS_100BASETX_FDPLX BIT14 // 100Mbps Full-Duplex ability +#define PHYSTS_100BASE_T4 BIT15 // Base T4 ability + +// PHY Auto-Negotiation advertisement +#define PHYANA_SEL_MASK ((UINT32)0x1F) // Link type selector +#define PHYANA_CSMA BIT0 // Advertise CSMA capability +#define PHYANA_10BASET BIT5 // Advertise 10BASET capability +#define PHYANA_10BASETFD BIT6 // Advertise 10BASET Full duplex capability +#define PHYANA_100BASETX BIT7 // Advertise 100BASETX capability +#define PHYANA_100BASETXFD BIT8 // Advertise 100 BASETX Full duplex capability +#define PHYANA_100BASET4 BIT9 // Advertise 100 BASETX Full duplex capability +#define PHYANA_PAUSE_OP_MASK (3 << 10) // Advertise PAUSE frame capability +#define PHYANA_REMOTE_FAULT BIT13 // Remote fault detected + + +// PHY Auto-Negotiation Link Partner Ability + +// PHY Auto-Negotiation Expansion + +// PHY Mode control/status + +// PHY Special Modes + +// PHY Special control/status + +// PHY Interrupt Source Flags + +// PHY Interrupt Mask + +// PHY Super Special control/status +#define PHYSSCS_HCDSPEED_MASK (7 << 2) // Speed indication +#define PHYSSCS_AUTODONE BIT12 // Auto-Negotiation Done + + +// MAC control register bits +#define MACCR_RX_EN BIT2 // Enable Receiver bit +#define MACCR_TX_EN BIT3 // Enable Transmitter bit +#define MACCR_DFCHK BIT5 // Deferral Check bit +#define MACCR_PADSTR BIT8 // Automatic Pad Stripping bit +#define MACCR_BOLMT_MASK (0xC0) // Back-Off limit mask +#define MACCR_DISRTY BIT10 // Disable Transmit Retry bit +#define MACCR_BCAST BIT11 // Disable Broadcast Frames bit +#define MACCR_LCOLL BIT12 // Late Collision Control bit +#define MACCR_HPFILT BIT13 // Hash/Perfect Filtering Mode bit +#define MACCR_HO BIT15 // Hash Only Filtering Mode +#define MACCR_PASSBAD BIT16 // Receive all frames that passed filter bit +#define MACCR_INVFILT BIT17 // Enable Inverse Filtering bit +#define MACCR_PRMS BIT18 // Promiscuous Mode bit +#define MACCR_MCPAS BIT19 // Pass all Multicast packets bit +#define MACCR_FDPX BIT20 // Full Duplex Mode bit +#define MACCR_LOOPBK BIT21 // Loopback operation mode bit +#define MACCR_RCVOWN BIT23 // Disable Receive Own frames bit +#define MACCR_RX_ALL BIT31 // Receive all Packets and route to Filter + +// Wake-Up Control and Status Register +#define WUCSR_MPEN BIT1 // Magic Packet enable (allow wake from Magic P) +#define WUCSR_WUEN BIT2 // Allow remote wake up using Wake-Up Frames +#define WUCSR_MPR_MASK (0x10) // Received Magic Packet +#define WUCSR_WUFR_MASK (0x20) // Received Wake-Up Frame +#define WUCSR_GUE BIT9 // Enable wake on global unicast frames + +// RX Configuration Register bits +#define RXCFG_RXDOFF_MASK (0x1F00) // Rx Data Offset in Bytes +#define RXCFG_RX_DUMP BIT15 // Clear Rx data and status FIFOs +#define RXCFG_RX_DMA_CNT_MASK (0x0FFF0000) // Amount of data to be read from Rx FIFO +#define RXCFG_RX_END_ALIGN_MASK (0xC0000000) // Alignment to preserve + +// TX Configuration Register bits +#define TXCFG_STOP_TX BIT0 // Stop the transmitter +#define TXCFG_TX_ON BIT1 // Start the transmitter +#define TXCFG_TXSAO BIT2 // Tx Status FIFO full +#define TXCFG_TXD_DUMP BIT14 // Clear Tx Data FIFO +#define TXCFG_TXS_DUMP BIT15 // Clear Tx Status FIFO + +// Rx FIFO Information Register bits +#define RXFIFOINF_RXDUSED_MASK (0xFFFF) // Rx Data FIFO Used Space +#define RXFIFOINF_RXSUSED_MASK (0xFF0000) // Rx Status FIFO Used Space + +// Tx FIFO Information Register bits +#define TXFIFOINF_TDFREE_MASK (0xFFFF) // Tx Data FIFO Free Space +#define TXFIFOINF_TXSUSED_MASK (0xFF0000) // Tx Status FIFO Used Space + +// E2P Register +#define E2P_EPC_BUSY BIT31 +#define E2P_EPC_TIMEOUT BIT9 +#define E2P_EPC_MAC_ADDRESS_LOADED BIT8 + +// GPIO Configuration register +#define GPIO_GPIO0_PUSH_PULL BIT16 +#define GPIO_GPIO1_PUSH_PULL BIT17 +#define GPIO_GPIO2_PUSH_PULL BIT18 +#define GPIO_LED1_ENABLE BIT28 +#define GPIO_LED2_ENABLE BIT29 +#define GPIO_LED3_ENABLE BIT30 + +// MII_ACC bits +#define MII_ACC_MII_BUSY BIT0 +#define MII_ACC_MII_WRITE BIT1 +#define MII_ACC_MII_READ 0 + +#define MII_ACC_PHY_VALUE BIT11 +#define MII_ACC_MII_REG_INDEX(index) (((index) & 0x1F) << 6) + +// +// PHY Control Indexes +// +#define PHY_INDEX_BASIC_CTRL 0 +#define PHY_INDEX_BASIC_STATUS 1 +#define PHY_INDEX_ID1 2 +#define PHY_INDEX_ID2 3 +#define PHY_INDEX_AUTO_NEG_ADVERT 4 +#define PHY_INDEX_AUTO_NEG_LINK_ABILITY 5 +#define PHY_INDEX_AUTO_NEG_EXP 6 +#define PHY_INDEX_MODE 17 +#define PHY_INDEX_SPECIAL_MODES 18 +#define PHY_INDEX_SPECIAL_CTLR 27 +#define PHY_INDEX_INT_SRC 29 +#define PHY_INDEX_INT_MASK 30 +#define PHY_INDEX_SPECIAL_PHY_CTLR 31 + +// Indirect MAC Indexes +#define INDIRECT_MAC_INDEX_CR 1 +#define INDIRECT_MAC_INDEX_ADDRH 2 +#define INDIRECT_MAC_INDEX_ADDRL 3 +#define INDIRECT_MAC_INDEX_HASHH 4 +#define INDIRECT_MAC_INDEX_HASHL 5 +#define INDIRECT_MAC_INDEX_MII_ACC 6 +#define INDIRECT_MAC_INDEX_MII_DATA 7 + +// +// MAC CSR Synchronizer Command register +// +#define MAC_CSR_BUSY BIT31 +#define MAC_CSR_READ BIT30 +#define MAC_CSR_WRITE 0 +#define MAC_CSR_ADDR(Addr) ((Addr) & 0xFF) + +// +// TX Packet Format +// +#define TX_CMD_A_COMPLETION_INT BIT31 +#define TX_CMD_A_START_OFFSET(off) (((off) & 0x1f) << 16) +#define TX_CMD_A_FIRST_SEGMENT BIT13 +#define TX_CMD_A_LAST_SEGMENT BIT12 +#define TX_CMD_A_BUFF_SIZE(size) ((size) & 0x000003FF) +#define TX_CMD_B_PACKET_TAG(tag) ((tag) << 16) +#define TX_CMD_B_PACKET_LENGTH(size) ((size) & 0x000003FF) + +// +// Conditional compilation flags +// +//#define USE_TX_BUFFER +//#define EVAL_PERFORMANCE + + +#endif /* __LAN9118_DXE_HDR_H__ */ -- cgit v1.2.3 From 06e741539970a3b4307a66d080cd13c3082c2952 Mon Sep 17 00:00:00 2001 From: "Reece R. Pollack" Date: Wed, 25 Sep 2013 23:51:34 -0400 Subject: ArmPlatformPkg: Added LAN91x Dxe driver Added a driver for the SMSC LAN91x Ethernet controllers, such as the 91C111 emulated in the ARM RTSM development simulators. Note that per-CPU support patches are committed in their respective branches rather than here. Signed-off-by: Reece R. Pollack --- ArmPlatformPkg/ArmPlatformPkg.dec | 6 +- ArmPlatformPkg/ArmVExpressPkg/ArmVExpress.dsc.inc | 2 +- ArmPlatformPkg/Drivers/LAN91xDxe/LAN91xDxe.c | 2235 +++++++++++++++++++++ ArmPlatformPkg/Drivers/LAN91xDxe/LAN91xDxe.inf | 58 + ArmPlatformPkg/Drivers/LAN91xDxe/LAN91xDxeHw.h | 278 +++ 5 files changed, 2577 insertions(+), 2 deletions(-) create mode 100644 ArmPlatformPkg/Drivers/LAN91xDxe/LAN91xDxe.c create mode 100644 ArmPlatformPkg/Drivers/LAN91xDxe/LAN91xDxe.inf create mode 100644 ArmPlatformPkg/Drivers/LAN91xDxe/LAN91xDxeHw.h diff --git a/ArmPlatformPkg/ArmPlatformPkg.dec b/ArmPlatformPkg/ArmPlatformPkg.dec index 2c4f88801..12412cb91 100644 --- a/ArmPlatformPkg/ArmPlatformPkg.dec +++ b/ArmPlatformPkg/ArmPlatformPkg.dec @@ -144,6 +144,11 @@ # gArmPlatformTokenSpaceGuid.PcdLan9118DxeBaseAddress|0x0|UINT32|0x000000FF + # + # LAN91x Ethernet Driver PCDs + # + gArmPlatformTokenSpaceGuid.PcdLan91xDxeBaseAddress|0x0|UINT32|0x000000FE + [PcdsFixedAtBuild.ARM] # Stack for CPU Cores in Secure Monitor Mode gArmPlatformTokenSpaceGuid.PcdCPUCoresSecMonStackBase|0|UINT32|0x00000007 @@ -155,4 +160,3 @@ # and PcdCPUCoreSecSecondaryStackSize gArmPlatformTokenSpaceGuid.PcdCPUCoresSecMonStackBase|0|UINT32|0x00000007 gArmPlatformTokenSpaceGuid.PcdCPUCoreSecMonStackSize|0x0|UINT32|0x00000008 - diff --git a/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress.dsc.inc b/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress.dsc.inc index fe0604bd5..1568c9d84 100644 --- a/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress.dsc.inc +++ b/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress.dsc.inc @@ -367,4 +367,4 @@ MdeModulePkg/Universal/Network/UefiPxeBcDxe/UefiPxeBcDxe.inf MdeModulePkg/Universal/Network/IScsiDxe/IScsiDxe.inf ArmPlatformPkg/Drivers/LAN9118Dxe/LAN9118Dxe.inf - + ArmPlatformPkg/Drivers/LAN91xDxe/LAN91xDxe.inf diff --git a/ArmPlatformPkg/Drivers/LAN91xDxe/LAN91xDxe.c b/ArmPlatformPkg/Drivers/LAN91xDxe/LAN91xDxe.c new file mode 100644 index 000000000..1f17e73f0 --- /dev/null +++ b/ArmPlatformPkg/Drivers/LAN91xDxe/LAN91xDxe.c @@ -0,0 +1,2235 @@ +/** @file +* SMSC LAN91x series Network Controller Driver. +* +* Copyright (c) 2013 Linaro.org +* +* Derived from the LAN9118 driver. Original sources +* Copyright (c) 2012-2013, 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. +* +**/ + +#include +#include +#include + +// Protocols used by this driver +#include +#include +#include +#include + +// Libraries used by this driver +#include +#include +#include +#include +#include +#include +#include +#include + +// Hardware register definitions +#include "LAN91xDxeHw.h" + +// Debugging output options +//#define LAN91X_PRINT_REGISTERS 1 +//#define LAN91X_PRINT_PACKET_HEADERS 1 +//#define LAN91X_PRINT_RECEIVE_FILTERS 1 + +// Chip power-down option -- UNTESTED +//#define LAN91X_POWER_DOWN 1 + +/*--------------------------------------------------------------------------------------------------------------------- + + LAN91x Information Structure + +---------------------------------------------------------------------------------------------------------------------*/ +typedef struct _LAN91X_DRIVER { + // Driver signature + UINT32 Signature; + EFI_HANDLE ControllerHandle; + + // EFI SNP protocol instances + EFI_SIMPLE_NETWORK_PROTOCOL Snp; + EFI_SIMPLE_NETWORK_MODE SnpMode; + + // EFI Snp statistics instance + EFI_NETWORK_STATISTICS Stats; + + // Transmit Buffer recycle queue +#define TX_QUEUE_DEPTH 16 + VOID *TxQueue[TX_QUEUE_DEPTH]; + UINTN TxQueHead; + UINTN TxQueTail; + + // Register access variables + UINTN IoBase; // I/O Base Address + UINT8 Revision; // Chip Revision Number + INT8 PhyAd; // Phy Address + UINT8 BankSel; // Currently selected register bank + +} LAN91X_DRIVER; + +#define LAN91X_NO_PHY (-1) // PhyAd value if PHY not detected + +#define LAN91X_SIGNATURE SIGNATURE_32('S', 'M', '9', '1') +#define INSTANCE_FROM_SNP_THIS(a) CR(a, LAN91X_DRIVER, Snp, LAN91X_SIGNATURE) + +#define LAN91X_STALL 2 +#define LAN91X_MEMORY_ALLOC_POLLS 100 // Max times to poll for memory allocation +#define LAN91X_PKT_OVERHEAD 6 // Overhead bytes in packet buffer + +// Synchronization TPLs +#define LAN91X_TPL TPL_CALLBACK + +// Most common CRC32 Polynomial for little endian machines +#define CRC_POLYNOMIAL 0xEDB88320 + + +typedef struct { + MAC_ADDR_DEVICE_PATH Lan91x; + EFI_DEVICE_PATH_PROTOCOL End; +} LAN91X_DEVICE_PATH; + +LAN91X_DEVICE_PATH Lan91xPathTemplate = { + { + { + MESSAGING_DEVICE_PATH, MSG_MAC_ADDR_DP, + { (UINT8) (sizeof(MAC_ADDR_DEVICE_PATH)), (UINT8) ((sizeof(MAC_ADDR_DEVICE_PATH)) >> 8) } + }, + { 0 }, + 0 + }, + { + END_DEVICE_PATH_TYPE, + END_ENTIRE_DEVICE_PATH_SUBTYPE, + sizeof(EFI_DEVICE_PATH_PROTOCOL), + 0 + } +}; + +// Chip ID numbers and name strings +#define CHIP_9192 3 +#define CHIP_9194 4 +#define CHIP_9195 5 +#define CHIP_9196 6 +#define CHIP_91100 7 +#define CHIP_91100FD 8 +#define CHIP_91111FD 9 + +STATIC CHAR16 CONST * CONST ChipIds[ 16 ] = { + NULL, NULL, NULL, + /* 3 */ L"SMC91C90/91C92", + /* 4 */ L"SMC91C94", + /* 5 */ L"SMC91C95", + /* 6 */ L"SMC91C96", + /* 7 */ L"SMC91C100", + /* 8 */ L"SMC91C100FD", + /* 9 */ L"SMC91C11xFD", + NULL, NULL, NULL, + NULL, NULL, NULL +}; + + +/* ------------------ TxBuffer Queue functions ------------------- */ + +#define TxQueNext(off) ((((off) + 1) >= TX_QUEUE_DEPTH) ? 0 : ((off) + 1)) + +STATIC +BOOLEAN +TxQueInsert ( + IN LAN91X_DRIVER *LanDriver, + IN VOID *Buffer + ) +{ + + if (TxQueNext (LanDriver->TxQueTail) == LanDriver->TxQueHead) { + return FALSE; + } + + LanDriver->TxQueue[LanDriver->TxQueTail] = Buffer; + LanDriver->TxQueTail = TxQueNext (LanDriver->TxQueTail); + + return TRUE; +} + +STATIC +VOID +*TxQueRemove ( + IN LAN91X_DRIVER *LanDriver + ) +{ + VOID *Buffer; + + if (LanDriver->TxQueTail == LanDriver->TxQueHead) { + return NULL; + } + + Buffer = LanDriver->TxQueue[LanDriver->TxQueHead]; + LanDriver->TxQueue[LanDriver->TxQueHead] = NULL; + LanDriver->TxQueHead = TxQueNext (LanDriver->TxQueHead); + + return Buffer; +} + +/* ------------------ MAC Address Hash Calculations ------------------- */ + +/* +** Generate a hash value from a multicast address +** +** This uses the Ethernet standard CRC32 algorithm +** +** INFO USED: +** 1: http://en.wikipedia.org/wiki/Cyclic_redundancy_check +** +** 2: http://www.erg.abdn.ac.uk/~gorry/eg3567/dl-pages/crc.html +** +** 3: http://en.wikipedia.org/wiki/Computation_of_CRC +*/ +STATIC +UINT32 +MulticastHash ( + IN EFI_MAC_ADDRESS *Mac, + IN UINT32 AddrLen + ) +{ + UINT32 Iter; + UINT32 Remainder; + UINT32 Crc32; + UINT8 *Addr; + + // 0xFFFFFFFF is standard seed for Ethernet + Remainder = 0xFFFFFFFF; + + // Generate the remainder byte-by-byte (LSB first) + Addr = &Mac->Addr[0]; + while (AddrLen-- > 0) { + Remainder ^= *Addr++; + for (Iter = 0; Iter < 8; ++Iter) { + // Check if exponent is set + if ((Remainder & 1) != 0) { + Remainder = (Remainder >> 1) ^ CRC_POLYNOMIAL; + } else { + Remainder = (Remainder >> 1) ^ 0; + } + } + } + + // Reverse the bits of the remainder + Crc32 = 0; + for (Iter = 0; Iter < 32; ++Iter) { + Crc32 <<= 1; + Crc32 |= Remainder & 1; + Remainder >>= 1; + } + return Crc32; +} + + +/* ---------------- Banked Register Operations ------------------ */ + +// Select the proper I/O bank +STATIC +VOID +SelectIoBank ( + LAN91X_DRIVER *LanDriver, + UINTN Register + ) +{ + UINT8 Bank; + + Bank = RegisterToBank (Register); + + // Select the proper I/O bank + if (LanDriver->BankSel != Bank) { + MmioWrite16 (LanDriver->IoBase + LAN91X_BANK_OFFSET, Bank); + LanDriver->BankSel = Bank; + } +} + +// Read a 16-bit I/O-space register +STATIC +UINT16 +ReadIoReg16 ( + LAN91X_DRIVER *LanDriver, + UINTN Register + ) +{ + UINT8 Offset; + + // Select the proper I/O bank + SelectIoBank (LanDriver, Register); + + // Read the requested register + Offset = RegisterToOffset (Register); + return MmioRead16 (LanDriver->IoBase + Offset); +} + +// Write a 16-bit I/O-space register +STATIC +UINT16 +WriteIoReg16 ( + LAN91X_DRIVER *LanDriver, + UINTN Register, + UINT16 Value + ) +{ + UINT8 Offset; + + // Select the proper I/O bank + SelectIoBank (LanDriver, Register); + + // Write the requested register + Offset = RegisterToOffset (Register); + return MmioWrite16 (LanDriver->IoBase + Offset, Value); +} + +// Read an 8-bit I/O-space register +STATIC +UINT8 +ReadIoReg8 ( + LAN91X_DRIVER *LanDriver, + UINTN Register + ) +{ + UINT8 Offset; + + // Select the proper I/O bank + SelectIoBank (LanDriver, Register); + + // Read the requested register + Offset = RegisterToOffset (Register); + return MmioRead8 (LanDriver->IoBase + Offset); +} + +// Write an 8-bit I/O-space register +STATIC +UINT8 +WriteIoReg8 ( + LAN91X_DRIVER *LanDriver, + UINTN Register, + UINT8 Value + ) +{ + UINT8 Offset; + + // Select the proper I/O bank + SelectIoBank (LanDriver, Register); + + // Write the requested register + Offset = RegisterToOffset (Register); + return MmioWrite8 (LanDriver->IoBase + Offset, Value); +} + + +/* ---------------- MII/PHY Access Operations ------------------ */ + +#define LAN91X_MDIO_STALL 1 + +STATIC +VOID +MdioOutput ( + LAN91X_DRIVER *LanDriver, + UINTN Bits, + UINT32 Value + ) +{ + UINT16 MgmtReg; + UINT32 Mask; + + MgmtReg = ReadIoReg16 (LanDriver, LAN91X_MGMT); + MgmtReg &= ~MGMT_MCLK; + MgmtReg |= MGMT_MDOE; + + for (Mask = (1 << (Bits - 1)); Mask != 0; Mask >>= 1) { + if ((Value & Mask) != 0) { + MgmtReg |= MGMT_MDO; + } else { + MgmtReg &= ~MGMT_MDO; + } + + WriteIoReg16 (LanDriver, LAN91X_MGMT, MgmtReg); + gBS->Stall (LAN91X_MDIO_STALL); + WriteIoReg16 (LanDriver, LAN91X_MGMT, MgmtReg | MGMT_MCLK); + gBS->Stall (LAN91X_MDIO_STALL); + } +} +#define PHY_OUTPUT_TIME (2 * LAN91X_MDIO_STALL) + +STATIC +UINT32 +MdioInput ( + LAN91X_DRIVER *LanDriver, + UINTN Bits + ) +{ + UINT16 MgmtReg; + UINT32 Mask; + UINT32 Value; + + MgmtReg = ReadIoReg16 (LanDriver, LAN91X_MGMT); + MgmtReg &= ~(MGMT_MDOE | MGMT_MCLK | MGMT_MDO); + WriteIoReg16 (LanDriver, LAN91X_MGMT, MgmtReg); + + Value = 0; + for (Mask = (1 << (Bits - 1)); Mask != 0; Mask >>= 1) { + if ((ReadIoReg16 (LanDriver, LAN91X_MGMT) & MGMT_MDI) != 0) { + Value |= Mask; + } + + WriteIoReg16 (LanDriver, LAN91X_MGMT, MgmtReg); + gBS->Stall (LAN91X_MDIO_STALL); + WriteIoReg16 (LanDriver, LAN91X_MGMT, MgmtReg | MGMT_MCLK); + gBS->Stall (LAN91X_MDIO_STALL); + } + + return Value; +} +#define PHY_INPUT_TIME (2 * LAN91X_MDIO_STALL) + +STATIC +VOID +MdioIdle ( + LAN91X_DRIVER *LanDriver + ) +{ + UINT16 MgmtReg; + + MgmtReg = ReadIoReg16 (LanDriver, LAN91X_MGMT); + MgmtReg &= ~(MGMT_MDOE | MGMT_MCLK | MGMT_MDO); + WriteIoReg16 (LanDriver, LAN91X_MGMT, MgmtReg); +} + +// Write to a PHY register +STATIC +VOID +WritePhyReg16 ( + LAN91X_DRIVER *LanDriver, + UINTN RegAd, + UINT16 Value + ) +{ + // Bit-bang the MII Serial Frame write operation + MdioOutput (LanDriver, 32, 0xffffffff); // Send 32 Ones as a preamble + MdioOutput (LanDriver, 2, 0x01); // Send Start (01) + MdioOutput (LanDriver, 2, 0x01); // Send Write (01) + MdioOutput (LanDriver, 5, LanDriver->PhyAd); // Send PHYAD[4:0] + MdioOutput (LanDriver, 5, RegAd); // Send REGAD[4:0] + MdioOutput (LanDriver, 2, 0x02); // Send TurnAround (10) + MdioOutput (LanDriver, 16, Value); // Write 16 data bits + + // Idle the MDIO bus + MdioIdle (LanDriver); +} +// Calculate approximate time to write a PHY register in microseconds +#define PHY_WRITE_TIME ((32 + 2 + 2 + 5 + 5 + 2 + 16) * PHY_OUTPUT_TIME) + +// Read from a PHY register +STATIC +UINT16 +ReadPhyReg16 ( + LAN91X_DRIVER *LanDriver, + UINTN RegAd + ) +{ + UINT32 Value; + + // Bit-bang the MII Serial Frame read operation + MdioOutput (LanDriver, 32, 0xffffffff); // Send 32 Ones as a preamble + MdioOutput (LanDriver, 2, 0x01); // Send Start (01) + MdioOutput (LanDriver, 2, 0x02); // Send Read (10) + MdioOutput (LanDriver, 5, LanDriver->PhyAd); // Send PHYAD[4:0] + MdioOutput (LanDriver, 5, RegAd); // Send REGAD[4:0] + + (VOID) MdioInput (LanDriver, 2); // Discard TurnAround bits + Value = MdioInput (LanDriver, 16); // Read 16 data bits + + // Idle the MDIO bus + MdioIdle (LanDriver); + + return (Value & 0xffff); +} +// Calculate approximate time to read a PHY register in microseconds +#define PHY_READ_TIME (((32 + 2 + 2 + 5 + 5) * PHY_OUTPUT_TIME) + \ + ((2 + 16) * PHY_INPUT_TIME)) + + +/* ---------------- Debug Functions ------------------ */ + +#ifdef LAN91X_PRINT_REGISTERS +STATIC +VOID +PrintIoRegisters ( + IN LAN91X_DRIVER *LanDriver + ) +{ + UINTN Bank; + UINTN Offset; + UINT16 Value; + + DEBUG((EFI_D_ERROR, "\nLAN91x I/O Register Dump:\n")); + + // Print currrent bank select register + Value = MmioRead16 (LanDriver->IoBase + LAN91X_BANK_OFFSET); + DEBUG((EFI_D_ERROR, " BankSel: %d Bank Register %04x (%d)\n", + LanDriver->BankSel, Value, Value & 0x0007)); + + // Print all I/O registers + for (Offset = 0; Offset < 0x0e; Offset += 2) { + DEBUG((EFI_D_ERROR, " %02x:", Offset)); + for (Bank = 0; Bank <= 3; ++Bank) { + DEBUG((EFI_D_ERROR, " %04x", ReadIoReg16 (LanDriver, MakeRegister (Bank, Offset)))); + } + DEBUG((EFI_D_ERROR, "\n")); + } +} + +STATIC +VOID +PrintPhyRegisters ( + IN LAN91X_DRIVER *LanDriver + ) +{ + UINTN RegNum; + + DEBUG((EFI_D_ERROR, "\nLAN91x Phy %d Register Dump:\n", LanDriver->PhyAd)); + + // Print all Phy registers + for (RegNum = 0; RegNum <= 5; ++RegNum) { + DEBUG((EFI_D_ERROR, " %2d: %04x\n", + RegNum, + ReadPhyReg16 (LanDriver, RegNum) + )); + } + for (RegNum = 16; RegNum <= 20; ++RegNum) { + DEBUG((EFI_D_ERROR, " %2d: %04x\n", + RegNum, + ReadPhyReg16 (LanDriver, RegNum) + )); + } +} +#endif + +#if LAN91X_PRINT_PACKET_HEADERS +STATIC +VOID +PrintIpDgram ( + IN CONST VOID *DstMac, + IN CONST VOID *SrcMac, + IN CONST VOID *Proto, + IN CONST VOID *IpDgram + ) +{ + CONST UINT8 *Ptr; + UINT16 SrcPort; + UINT16 DstPort; + + Ptr = DstMac; + DEBUG((EFI_D_ERROR, " Dst: %02x-%02x-%02x", + Ptr[0], Ptr[1], Ptr[2])); + DEBUG((EFI_D_ERROR, "-%02x-%02x-%02x", + Ptr[3], Ptr[4], Ptr[5])); + + Ptr = SrcMac; + DEBUG((EFI_D_ERROR, " Src: %02x-%02x-%02x", + Ptr[0], Ptr[1], Ptr[2])); + DEBUG((EFI_D_ERROR, "-%02x-%02x-%02x", + Ptr[3], Ptr[4], Ptr[5])); + + Ptr = Proto; + DEBUG((EFI_D_ERROR, " Proto: %02x%02x\n", + Ptr[0], Ptr[1])); + + Ptr = IpDgram; + switch (Ptr[9]) { + case EFI_IP_PROTO_ICMP: + DEBUG((EFI_D_ERROR, " ICMP")); + break; + case EFI_IP_PROTO_TCP: + DEBUG((EFI_D_ERROR, " TCP")); + break; + case EFI_IP_PROTO_UDP: + DEBUG((EFI_D_ERROR, " UDP")); + break; + default: + DEBUG((EFI_D_ERROR, " IpProto %d\n", Ptr[9])); + return; + } + + DEBUG((EFI_D_ERROR, " SrcIp: %d.%d.%d.%d", + Ptr[12], Ptr[13], Ptr[14], Ptr[15])); + DEBUG((EFI_D_ERROR, " DstIp: %d.%d.%d.%d", + Ptr[16], Ptr[17], Ptr[18], Ptr[19])); + + SrcPort = (Ptr[20] << 8) | Ptr[21]; + DstPort = (Ptr[22] << 8) | Ptr[23]; + DEBUG((EFI_D_ERROR, " SrcPort: %d DstPort: %d\n", SrcPort, DstPort)); +} +#endif + + +/* ---------------- PHY Management Operations ----------------- */ + +STATIC +EFI_STATUS +PhyDetect ( + IN LAN91X_DRIVER *LanDriver + ) +{ + UINT16 PhyId1; + UINT16 PhyId2; + + for (LanDriver->PhyAd = 0x1f; LanDriver->PhyAd >= 0 ; --LanDriver->PhyAd) { + PhyId1 = ReadPhyReg16 (LanDriver, PHY_INDEX_ID1); + PhyId2 = ReadPhyReg16 (LanDriver, PHY_INDEX_ID2); + + if ((PhyId1 != 0x0000) && (PhyId1 != 0xffff) && + (PhyId2 != 0x0000) && (PhyId2 != 0xffff)) { + if ((PhyId1 == 0x0016) && ((PhyId2 & 0xfff0) == 0xf840)) { + DEBUG((EFI_D_ERROR, "LAN91x: PHY type LAN83C183 (LAN91C111 Internal)\n")); + } else if ((PhyId1 == 0x0282) && ((PhyId2 & 0xfff0) == 0x1c50)) { + DEBUG((EFI_D_ERROR, "LAN91x: PHY type LAN83C180\n")); + } else { + DEBUG((EFI_D_ERROR, "LAN91x: PHY id %04x:%04x\n", PhyId1, PhyId2)); + } + return EFI_SUCCESS; + } + } + + DEBUG((EFI_D_ERROR, "LAN91x: PHY detection failed\n")); + return EFI_NO_MEDIA; +} + + +// Check the Link Status and take appropriate action +STATIC +BOOLEAN +CheckLinkStatus ( + IN LAN91X_DRIVER *LanDriver + ) +{ + UINT16 PhyStatus; + + // Get the PHY Status + PhyStatus = ReadPhyReg16 (LanDriver, PHY_INDEX_BASIC_STATUS); + + return (PhyStatus & PHYSTS_LINK_STS) != 0; +} + + +// Do auto-negotiation +STATIC +EFI_STATUS +PhyAutoNegotiate ( + IN LAN91X_DRIVER *LanDriver + ) +{ + UINTN Retries; + UINT16 PhyControl; + UINT16 PhyStatus; + UINT16 PhyAdvert; + + // If there isn't a PHY, don't try to reset it + if (LanDriver->PhyAd == LAN91X_NO_PHY) { + return EFI_SUCCESS; + } + + // Next check that auto-negotiation is supported + PhyStatus = ReadPhyReg16 (LanDriver, PHY_INDEX_BASIC_STATUS); + if ((PhyStatus & PHYSTS_AUTO_CAP) == 0) { + return EFI_SUCCESS; + } + + // Translate capabilities to advertise + PhyAdvert = PHYANA_CSMA; + + if ((PhyStatus & PHYSTS_10BASET_HDPLX) != 0) { + PhyAdvert |= PHYANA_10BASET; + } + if ((PhyStatus & PHYSTS_10BASET_FDPLX) != 0) { + PhyAdvert |= PHYANA_10BASETFD; + } + if ((PhyStatus & PHYSTS_100BASETX_HDPLX) != 0) { + PhyAdvert |= PHYANA_100BASETX; + } + if ((PhyStatus & PHYSTS_100BASETX_FDPLX) != 0) { + PhyAdvert |= PHYANA_100BASETXFD; + } + if ((PhyStatus & PHYSTS_100BASE_T4) != 0) { + PhyAdvert |= PHYANA_100BASET4; + } + + // Set the capabilities to advertise + WritePhyReg16 (LanDriver, PHY_INDEX_AUTO_NEG_ADVERT, PhyAdvert); + (VOID) ReadPhyReg16 (LanDriver, PHY_INDEX_AUTO_NEG_ADVERT); + + // Restart Auto-Negotiation + PhyControl = ReadPhyReg16 (LanDriver, PHY_INDEX_BASIC_CTRL); + PhyControl &= ~(PHYCR_SPEED_SEL | PHYCR_DUPLEX_MODE); + PhyControl |= PHYCR_AUTO_EN | PHYCR_RST_AUTO; + WritePhyReg16 (LanDriver, PHY_INDEX_BASIC_CTRL, PhyControl); + + // Wait up to 2 seconds for the process to complete + Retries = 2000000 / (PHY_READ_TIME + 100); + while ((ReadPhyReg16 (LanDriver, PHY_INDEX_BASIC_STATUS) & PHYSTS_AUTO_COMP) == 0) { + if (--Retries == 0) { + DEBUG((EFI_D_ERROR, "LAN91x: PHY auto-negotiation timed-out\n")); + return EFI_TIMEOUT; + } + gBS->Stall (100); + } + + return EFI_SUCCESS; +} + + +// Perform PHY software reset +STATIC +EFI_STATUS +PhySoftReset ( + IN LAN91X_DRIVER *LanDriver + ) +{ + UINTN Retries; + + // If there isn't a PHY, don't try to reset it + if (LanDriver->PhyAd == LAN91X_NO_PHY) { + return EFI_SUCCESS; + } + + // Request a PHY reset + WritePhyReg16 (LanDriver, PHY_INDEX_BASIC_CTRL, PHYCR_RESET); + + // The internal PHY will reset within 50ms. Allow 100ms. + Retries = 100000 / (PHY_READ_TIME + 100); + while (ReadPhyReg16 (LanDriver, PHY_INDEX_BASIC_CTRL) & PHYCR_RESET) { + if (--Retries == 0) { + DEBUG((EFI_D_ERROR, "LAN91x: PHY reset timed-out\n")); + return EFI_TIMEOUT; + } + gBS->Stall (100); + } + + return EFI_SUCCESS; +} + + +/* ---------------- General Operations ----------------- */ + +STATIC +EFI_MAC_ADDRESS +GetCurrentMacAddress ( + IN LAN91X_DRIVER *LanDriver + ) +{ + UINTN RegNum; + UINT8 *Addr; + EFI_MAC_ADDRESS MacAddress; + + SetMem (&MacAddress, sizeof(MacAddress), 0); + + Addr = &MacAddress.Addr[0]; + for (RegNum = LAN91X_IAR0; RegNum <= LAN91X_IAR5; ++RegNum) { + *Addr = ReadIoReg8 (LanDriver, RegNum); + ++Addr; + } + + return MacAddress; +} + +STATIC +EFI_STATUS +SetCurrentMacAddress ( + IN LAN91X_DRIVER *LanDriver, + IN EFI_MAC_ADDRESS *MacAddress + ) +{ + UINTN RegNum; + UINT8 *Addr; + + Addr = &MacAddress->Addr[0]; + for (RegNum = LAN91X_IAR0; RegNum <= LAN91X_IAR5; ++RegNum) { + WriteIoReg8 (LanDriver, RegNum, *Addr); + ++Addr; + } + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +MmuOperation ( + IN LAN91X_DRIVER *LanDriver, + IN UINTN MmuOp + ) +{ + UINTN Polls; + + WriteIoReg16 (LanDriver, LAN91X_MMUCR, MmuOp); + Polls = 100; + while ((ReadIoReg16 (LanDriver, LAN91X_MMUCR) & MMUCR_BUSY) != 0) { + if (--Polls == 0) { + DEBUG((EFI_D_ERROR, "LAN91x: MMU operation %04x timed-out\n", MmuOp)); + return EFI_TIMEOUT; + } + gBS->Stall (LAN91X_STALL); + } + + return EFI_SUCCESS; +} + +// Read bytes from the DATA register +STATIC +EFI_STATUS +ReadIoData ( + IN LAN91X_DRIVER *LanDriver, + IN VOID *Buffer, + IN UINTN BufLen + ) +{ + UINT8 *Ptr; + + Ptr = Buffer; + for (; BufLen > 0; --BufLen) { + *Ptr = ReadIoReg8 (LanDriver, LAN91X_DATA0); + ++Ptr; + } + + return EFI_SUCCESS; +} + +// Write bytes to the DATA register +STATIC +EFI_STATUS +WriteIoData ( + IN LAN91X_DRIVER *LanDriver, + IN VOID *Buffer, + IN UINTN BufLen + ) +{ + UINT8 *Ptr; + + Ptr = Buffer; + for (; BufLen > 0; --BufLen) { + WriteIoReg8 (LanDriver, LAN91X_DATA0, *Ptr); + ++Ptr; + } + + return EFI_SUCCESS; +} + +// Disable the interface +STATIC +EFI_STATUS +ChipDisable ( + IN LAN91X_DRIVER *LanDriver + ) +{ +#ifdef LAN91X_POWER_DOWN + UINT16 Val16; +#endif + + // Stop Rx and Tx operations + WriteIoReg16 (LanDriver, LAN91X_RCR, RCR_CLEAR); + WriteIoReg16 (LanDriver, LAN91X_TCR, TCR_CLEAR); + +#ifdef LAN91X_POWER_DOWN + // Power-down the chip + Val16 = ReadIoReg16 (LanDriver, LAN91X_CR); + Val16 &= ~CR_EPH_POWER_EN; + WriteIoReg16 (LanDriver, LAN91X_CR, Val16); +#endif + + return EFI_SUCCESS; +} + +// Enable the interface +STATIC +EFI_STATUS +ChipEnable ( + IN LAN91X_DRIVER *LanDriver + ) +{ +#ifdef LAN91X_POWER_DOWN + UINT16 Val16; + + // Power-up the chip + Val16 = ReadIoReg16 (LanDriver, LAN91X_CR); + Val16 |= CR_EPH_POWER_EN; + WriteIoReg16 (LanDriver, LAN91X_CR, Val16); + gBS->Stall (LAN91X_STALL); +#endif + + // Start Rx and Tx operations + WriteIoReg16 (LanDriver, LAN91X_TCR, TCR_DEFAULT); + WriteIoReg16 (LanDriver, LAN91X_RCR, RCR_DEFAULT); + + return EFI_SUCCESS; +} + + +// Perform software reset on the LAN91x +STATIC +EFI_STATUS +SoftReset ( + IN LAN91X_DRIVER *LanDriver + ) +{ + UINT16 Val16; + + // Issue the reset + WriteIoReg16 (LanDriver, LAN91X_RCR, RCR_SOFT_RST); + gBS->Stall (LAN91X_STALL); + WriteIoReg16 (LanDriver, LAN91X_RCR, RCR_CLEAR); + + // Set the configuration register + WriteIoReg16 (LanDriver, LAN91X_CR, CR_DEFAULT); + gBS->Stall (LAN91X_STALL); + + // Stop Rx and Tx + WriteIoReg16 (LanDriver, LAN91X_RCR, RCR_CLEAR); + WriteIoReg16 (LanDriver, LAN91X_TCR, TCR_CLEAR); + + // Initialize the Control Register + Val16 = ReadIoReg16 (LanDriver, LAN91X_CTR); + Val16 |= CTR_AUTO_REL; + WriteIoReg16 (LanDriver, LAN91X_CTR, Val16); + + // Reset the MMU + MmuOperation (LanDriver, MMUCR_OP_RESET_MMU); + + return EFI_SUCCESS; +} + +/* +** Probe() +** +** Validate that there is a LAN91x device. +** +*/ +STATIC +EFI_STATUS +Probe ( + IN LAN91X_DRIVER *LanDriver + ) +{ + UINT16 Bank; + UINT16 Val16; + CHAR16 CONST *ChipId; + UINTN ResetTime; + + // First check that the Bank Select register is valid + Bank = MmioRead16 (LanDriver->IoBase + LAN91X_BANK_OFFSET); + if ((Bank & 0xff00) != 0x3300) { + DEBUG((EFI_D_ERROR, "LAN91x: signature error: expecting 33xx, read %04x\n", Bank)); + return EFI_DEVICE_ERROR; + } + + // Try reading the revision register next + LanDriver->BankSel = 0xff; + Val16 = ReadIoReg16 (LanDriver, LAN91X_REV); + + Bank = MmioRead16 (LanDriver->IoBase + LAN91X_BANK_OFFSET); + if ((Bank & 0xff03) != 0x3303) { + DEBUG((EFI_D_ERROR, "LAN91x: signature error: expecting 33x3, read %04x\n", Bank)); + return EFI_DEVICE_ERROR; + } + + // Validate the revision register + if ((Val16 & 0xff00) != 0x3300) { + DEBUG((EFI_D_ERROR, "LAN91x: revision error: expecting 33xx, read %04x\n", Val16)); + return EFI_DEVICE_ERROR; + } + + ChipId = ChipIds[(Val16 >> 4) & 0x0f]; + if (ChipId == NULL) { + DEBUG((EFI_D_ERROR, "LAN91x: unrecognized revision: %04x\n", Val16)); + return EFI_DEVICE_ERROR; + } + DEBUG((EFI_D_ERROR, "LAN91x: detected chip %s rev %d\n", ChipId, Val16 & 0xf)); + LanDriver->Revision = Val16 & 0xff; + + // Reload from EEPROM to get the hardware MAC address + WriteIoReg16 (LanDriver, LAN91X_CTR, CTR_RESERVED | CTR_RELOAD); + ResetTime = 1000; + while ((ReadIoReg16 (LanDriver, LAN91X_CTR) & CTR_RELOAD) != 0) { + if (--ResetTime == 0) { + DEBUG((EFI_D_ERROR, "LAN91x: reload from EEPROM timed-out\n")); + WriteIoReg16 (LanDriver, LAN91X_CTR, CTR_RESERVED); + return EFI_DEVICE_ERROR; + } + gBS->Stall (LAN91X_STALL); + } + + // Read and save the Permanent MAC Address + LanDriver->SnpMode.PermanentAddress = GetCurrentMacAddress (LanDriver); + DEBUG((EFI_D_ERROR, //EFI_D_NET | EFI_D_INFO, + "LAN91x: HW MAC Address: %02x-%02x-%02x-%02x-%02x-%02x\n", + LanDriver->SnpMode.PermanentAddress.Addr[0], + LanDriver->SnpMode.PermanentAddress.Addr[1], + LanDriver->SnpMode.PermanentAddress.Addr[2], + LanDriver->SnpMode.PermanentAddress.Addr[3], + LanDriver->SnpMode.PermanentAddress.Addr[4], + LanDriver->SnpMode.PermanentAddress.Addr[5] + )); + + // Reset the device + SoftReset (LanDriver); + + // Try to detect a PHY + if (LanDriver->Revision > (CHIP_91100 << 4)) { + PhyDetect (LanDriver); + } else { + LanDriver->PhyAd = LAN91X_NO_PHY; + } + + return EFI_SUCCESS; +} + + + + +/*------------------ Simple Network Driver entry point functions ------------------*/ + +// Refer to the Simple Network Protocol section (21.1) +// in the UEFI 2.3.1 Specification for documentation. + +#define ReturnUnlock(s) do { Status = (s); goto exit_unlock; } while(0) + + +/* +** UEFI Start() function +** +*/ +EFI_STATUS +EFIAPI +SnpStart ( + IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp + ) +{ + EFI_SIMPLE_NETWORK_MODE *Mode; + EFI_TPL SavedTpl; + EFI_STATUS Status; + + // Check Snp instance + if (Snp == NULL) { + return EFI_INVALID_PARAMETER; + } + + // Serialize access to data and registers + SavedTpl = gBS->RaiseTPL (LAN91X_TPL); + Mode = Snp->Mode; + + // Check state of the driver + switch (Mode->State) { + case EfiSimpleNetworkStopped: + break; + case EfiSimpleNetworkStarted: + case EfiSimpleNetworkInitialized: + DEBUG((EFI_D_WARN, "LAN91x: Driver already started\n")); + ReturnUnlock (EFI_ALREADY_STARTED); + default: + DEBUG((EFI_D_ERROR, "LAN91x: Driver in an invalid state: %u\n", + (UINTN)Snp->Mode->State)); + ReturnUnlock (EFI_DEVICE_ERROR); + } + + // Set the Current MAC address + Mode->CurrentAddress = Mode->PermanentAddress; + + // Change state + Mode->State = EfiSimpleNetworkStarted; + Status = EFI_SUCCESS; + + // Restore TPL and return +exit_unlock: + gBS->RestoreTPL (SavedTpl); + return Status; +} + +/* +** UEFI Stop() function +** +*/ +EFI_STATUS +EFIAPI +SnpStop ( + IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp + ) +{ + LAN91X_DRIVER *LanDriver; + EFI_TPL SavedTpl; + EFI_STATUS Status; + + // Check Snp Instance + if (Snp == NULL) { + return EFI_INVALID_PARAMETER; + } + + // Serialize access to data and registers + SavedTpl = gBS->RaiseTPL (LAN91X_TPL); + + // Check state of the driver + switch (Snp->Mode->State) { + case EfiSimpleNetworkStarted: + case EfiSimpleNetworkInitialized: + break; + case EfiSimpleNetworkStopped: + DEBUG((EFI_D_WARN, "LAN91x: Driver not started\n")); + ReturnUnlock (EFI_NOT_STARTED); + default: + DEBUG((EFI_D_ERROR, "LAN91x: Driver in an invalid state: %u\n", + (UINTN)Snp->Mode->State)); + ReturnUnlock (EFI_DEVICE_ERROR); + } + + // Find the LanDriver structure + LanDriver = INSTANCE_FROM_SNP_THIS(Snp); + + // Stop the Tx and Rx + ChipDisable (LanDriver); + + // Change the state + Snp->Mode->State = EfiSimpleNetworkStopped; + Status = EFI_SUCCESS; + + // Restore TPL and return +exit_unlock: + gBS->RestoreTPL (SavedTpl); + return Status; +} + +/* +** UEFI Initialize() function +** +*/ +EFI_STATUS +EFIAPI +SnpInitialize ( + IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp, + IN UINTN RxBufferSize OPTIONAL, + IN UINTN TxBufferSize OPTIONAL + ) +{ + LAN91X_DRIVER *LanDriver; + EFI_TPL SavedTpl; + EFI_STATUS Status; + + // Check Snp Instance + if (Snp == NULL) { + return EFI_INVALID_PARAMETER; + } + + // Serialize access to data and registers + SavedTpl = gBS->RaiseTPL (LAN91X_TPL); + + // Check that driver was started but not initialised + switch (Snp->Mode->State) { + case EfiSimpleNetworkStarted: + break; + case EfiSimpleNetworkInitialized: + DEBUG((EFI_D_WARN, "LAN91x: Driver already initialized\n")); + ReturnUnlock (EFI_SUCCESS); + case EfiSimpleNetworkStopped: + DEBUG((EFI_D_WARN, "LAN91x: Driver not started\n")); + ReturnUnlock (EFI_NOT_STARTED); + default: + DEBUG((EFI_D_ERROR, "LAN91x: Driver in an invalid state: %u\n", + (UINTN)Snp->Mode->State)); + ReturnUnlock (EFI_DEVICE_ERROR); + } + + // Find the LanDriver structure + LanDriver = INSTANCE_FROM_SNP_THIS(Snp); + + // Initiate a software reset + Status = SoftReset (LanDriver); + if (EFI_ERROR(Status)) { + DEBUG((EFI_D_WARN, "LAN91x: Soft reset failed\n")); + ReturnUnlock (EFI_DEVICE_ERROR); + } + + // Initiate a PHY reset + if (PhySoftReset (LanDriver) < 0) { + Snp->Mode->State = EfiSimpleNetworkStopped; + DEBUG((EFI_D_WARN, "LAN91x: PHY soft reset timeout\n")); + ReturnUnlock (EFI_NOT_STARTED); + } + + // Do auto-negotiation + Status = PhyAutoNegotiate (LanDriver); + if (EFI_ERROR(Status)) { + DEBUG((EFI_D_WARN, "LAN91x: PHY auto-negotiation failed\n")); + } + + // Enable the receiver and transmitter + ChipEnable (LanDriver); + + // Now acknowledge all interrupts + WriteIoReg8 (LanDriver, LAN91X_IST, 0xFF); + + // Declare the driver as initialized + Snp->Mode->State = EfiSimpleNetworkInitialized; + Status = EFI_SUCCESS; + + // Restore TPL and return +exit_unlock: + gBS->RestoreTPL (SavedTpl); + return Status; +} + +/* +** UEFI Reset () function +** +*/ +EFI_STATUS +EFIAPI +SnpReset ( + IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp, + IN BOOLEAN Verification + ) +{ + LAN91X_DRIVER *LanDriver; + EFI_TPL SavedTpl; + EFI_STATUS Status; + + // Check Snp Instance + if (Snp == NULL) { + return EFI_INVALID_PARAMETER; + } + + // Serialize access to data and registers + SavedTpl = gBS->RaiseTPL (LAN91X_TPL); + + // Check that driver was started and initialised + switch (Snp->Mode->State) { + case EfiSimpleNetworkInitialized: + break; + case EfiSimpleNetworkStarted: + DEBUG((EFI_D_WARN, "LAN91x: Driver not yet initialized\n")); + ReturnUnlock (EFI_DEVICE_ERROR); + case EfiSimpleNetworkStopped: + DEBUG((EFI_D_WARN, "LAN91x: Driver not started\n")); + ReturnUnlock (EFI_NOT_STARTED); + default: + DEBUG((EFI_D_ERROR, "LAN91x: Driver in an invalid state: %u\n", + (UINTN)Snp->Mode->State)); + ReturnUnlock (EFI_DEVICE_ERROR); + } + + // Find the LanDriver structure + LanDriver = INSTANCE_FROM_SNP_THIS(Snp); + + // Initiate a software reset + if (EFI_ERROR (SoftReset (LanDriver))) { + DEBUG((EFI_D_WARN, "LAN91x: Soft reset failed\n")); + ReturnUnlock (EFI_DEVICE_ERROR); + } + + // Initiate a PHY reset + if (EFI_ERROR (PhySoftReset (LanDriver))) { + DEBUG((EFI_D_WARN, "LAN91x: PHY soft reset failed\n")); + ReturnUnlock (EFI_DEVICE_ERROR); + } + + // Enable the receiver and transmitter + Status = ChipEnable (LanDriver); + + // Restore TPL and return +exit_unlock: + gBS->RestoreTPL (SavedTpl); + return Status; +} + +/* +** UEFI Shutdown () function +** +*/ +EFI_STATUS +EFIAPI +SnpShutdown ( + IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp + ) +{ + LAN91X_DRIVER *LanDriver; + EFI_TPL SavedTpl; + EFI_STATUS Status; + + // Check Snp Instance + if (Snp == NULL) { + return EFI_INVALID_PARAMETER; + } + + // Serialize access to data and registers + SavedTpl = gBS->RaiseTPL (LAN91X_TPL); + + // First check that driver has already been initialized + switch (Snp->Mode->State) { + case EfiSimpleNetworkInitialized: + break; + case EfiSimpleNetworkStarted: + DEBUG((EFI_D_WARN, "LAN91x: Driver not yet initialized\n")); + ReturnUnlock (EFI_DEVICE_ERROR); + case EfiSimpleNetworkStopped: + DEBUG((EFI_D_WARN, "LAN91x: Driver in stopped state\n")); + ReturnUnlock (EFI_NOT_STARTED); + default: + DEBUG((EFI_D_ERROR, "LAN91x: Driver in an invalid state: %u\n", + (UINTN)Snp->Mode->State)); + ReturnUnlock (EFI_DEVICE_ERROR); + } + + // Find the LanDriver structure + LanDriver = INSTANCE_FROM_SNP_THIS(Snp); + + // Disable the interface + Status = ChipDisable (LanDriver); + + // Restore TPL and return +exit_unlock: + gBS->RestoreTPL (SavedTpl); + return Status; +} + + +/* +** 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 + ) +{ +#define MCAST_HASH_BYTES 8 + + LAN91X_DRIVER *LanDriver; + EFI_SIMPLE_NETWORK_MODE *SnpMode; + EFI_TPL SavedTpl; + EFI_STATUS Status; + UINTN i; + UINT32 Crc; + UINT16 RcvCtrl; + UINT8 McastHash[MCAST_HASH_BYTES]; + + // Check Snp Instance + if (Snp == NULL) { + return EFI_INVALID_PARAMETER; + } + + // Serialize access to data and registers + SavedTpl = gBS->RaiseTPL (LAN91X_TPL); + + // First check that driver has already been initialized + switch (Snp->Mode->State) { + case EfiSimpleNetworkInitialized: + break; + case EfiSimpleNetworkStarted: + DEBUG((EFI_D_WARN, "LAN91x: Driver not yet initialized\n")); + ReturnUnlock (EFI_DEVICE_ERROR); + case EfiSimpleNetworkStopped: + DEBUG((EFI_D_WARN, "LAN91x: Driver not started\n")); + ReturnUnlock (EFI_NOT_STARTED); + default: + DEBUG((EFI_D_ERROR, "LAN91x: Driver in an invalid state: %u\n", + (UINTN)Snp->Mode->State)); + ReturnUnlock (EFI_DEVICE_ERROR); + } + + // Find the LanDriver structure + LanDriver = INSTANCE_FROM_SNP_THIS(Snp); + SnpMode = Snp->Mode; + +#ifdef LAN91X_PRINT_RECEIVE_FILTERS + DEBUG((EFI_D_ERROR, "LAN91x:SnpReceiveFilters()\n")); + DEBUG((EFI_D_ERROR, " Enable = %08x\n", Enable)); + DEBUG((EFI_D_ERROR, " Disable = %08x\n", Disable)); + DEBUG((EFI_D_ERROR, " Reset = %d\n", Reset)); + DEBUG((EFI_D_ERROR, " NumMfilter = %d\n", NumMfilter)); + for (i = 0; i < NumMfilter; ++i) { + DEBUG((EFI_D_ERROR, + " [%2d] = %02x-%02x-%02x-%02x-%02x-%02x\n", + i, + Mfilter[i].Addr[0], + Mfilter[i].Addr[1], + Mfilter[i].Addr[2], + Mfilter[i].Addr[3], + Mfilter[i].Addr[4], + Mfilter[i].Addr[5])); + } +#endif + + // Update the Multicast Hash registers + if (Reset) { + // Clear the hash table + SetMem (McastHash, MCAST_HASH_BYTES, 0); + SnpMode->MCastFilterCount = 0; + } else { + // Read the current hash table + for (i = 0; i < MCAST_HASH_BYTES; ++i) { + McastHash[i] = ReadIoReg8 (LanDriver, LAN91X_MT0 + i); + } + // Set the new additions + for (i = 0; i < NumMfilter; ++i) { + Crc = MulticastHash (&Mfilter[i], NET_ETHER_ADDR_LEN); + McastHash[(Crc >> 29) & 0x3] |= 1 << ((Crc >> 26) & 0x3); + } + SnpMode->MCastFilterCount = NumMfilter; + } + // If the hash registers need updating, write them + if (Reset || NumMfilter > 0) { + for (i = 0; i < MCAST_HASH_BYTES; ++i) { + WriteIoReg8 (LanDriver, LAN91X_MT0 + i, McastHash[i]); + } + } + + RcvCtrl = ReadIoReg16 (LanDriver, LAN91X_RCR); + if ((Enable & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS) != 0) { + RcvCtrl |= RCR_PRMS; + SnpMode->ReceiveFilterSetting |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS; + } + if ((Disable & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS) != 0) { + RcvCtrl &= ~RCR_PRMS; + SnpMode->ReceiveFilterSetting &= ~EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS; + } + + if ((Enable & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST) != 0) { + RcvCtrl |= RCR_ALMUL; + SnpMode->ReceiveFilterSetting |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST; + } + if ((Disable & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST) != 0) { + RcvCtrl &= ~RCR_ALMUL; + SnpMode->ReceiveFilterSetting &= ~EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST; + } + WriteIoReg16 (LanDriver, LAN91X_RCR, RcvCtrl); + + Status = SetCurrentMacAddress (LanDriver, &SnpMode->CurrentAddress); + + // Restore TPL and return +exit_unlock: + gBS->RestoreTPL (SavedTpl); + return Status; +} + +/* +** UEFI StationAddress() function +** +*/ +EFI_STATUS +EFIAPI +SnpStationAddress ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *Snp, + IN BOOLEAN Reset, + IN EFI_MAC_ADDRESS *NewMac +) +{ + LAN91X_DRIVER *LanDriver; + EFI_TPL SavedTpl; + EFI_STATUS Status; + + // Check Snp instance + if (Snp == NULL) { + return EFI_INVALID_PARAMETER; + } + + // Serialize access to data and registers + SavedTpl = gBS->RaiseTPL (LAN91X_TPL); + + // Check that driver was started and initialised + switch (Snp->Mode->State) { + case EfiSimpleNetworkInitialized: + break; + case EfiSimpleNetworkStarted: + DEBUG((EFI_D_WARN, "LAN91x: Driver not yet initialized\n")); + ReturnUnlock (EFI_DEVICE_ERROR); + case EfiSimpleNetworkStopped: + DEBUG((EFI_D_WARN, "LAN91x: Driver not started\n")); + ReturnUnlock (EFI_NOT_STARTED); + default: + DEBUG((EFI_D_ERROR, "LAN91x: Driver in an invalid state: %u\n", + (UINTN)Snp->Mode->State)); + ReturnUnlock (EFI_DEVICE_ERROR); + } + + // Find the LanDriver structure + LanDriver = INSTANCE_FROM_SNP_THIS(Snp); + + if (Reset) { + Snp->Mode->CurrentAddress = Snp->Mode->PermanentAddress; + } else { + if (NewMac == NULL) { + ReturnUnlock (EFI_INVALID_PARAMETER); + } + Snp->Mode->CurrentAddress = *NewMac; + } + + Status = SetCurrentMacAddress (LanDriver, &Snp->Mode->CurrentAddress); + + // Restore TPL and return +exit_unlock: + gBS->RestoreTPL (SavedTpl); + return Status; +} + +/* +** UEFI Statistics() function +** +*/ +EFI_STATUS +EFIAPI +SnpStatistics ( + IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp, + IN BOOLEAN Reset, + IN OUT UINTN *StatSize, + OUT EFI_NETWORK_STATISTICS *Statistics + ) +{ + LAN91X_DRIVER *LanDriver; + EFI_TPL SavedTpl; + EFI_STATUS Status; + + // Check Snp instance + if (Snp == NULL) { + return EFI_INVALID_PARAMETER; + } + + // Check pointless condition + if ((!Reset) && (StatSize == NULL) && (Statistics == NULL)) { + return EFI_SUCCESS; + } + + // Check the parameters + if ((StatSize == NULL) && (Statistics != NULL)) { + return EFI_INVALID_PARAMETER; + } + + // Serialize access to data and registers + SavedTpl = gBS->RaiseTPL (LAN91X_TPL); + + // Check that driver was started and initialised + switch (Snp->Mode->State) { + case EfiSimpleNetworkInitialized: + break; + case EfiSimpleNetworkStarted: + DEBUG((EFI_D_WARN, "LAN91x: Driver not yet initialized\n")); + ReturnUnlock (EFI_DEVICE_ERROR); + case EfiSimpleNetworkStopped: + DEBUG((EFI_D_WARN, "LAN91x: Driver not started\n")); + ReturnUnlock (EFI_NOT_STARTED); + default: + DEBUG((EFI_D_ERROR, "LAN91x: Driver in an invalid state: %u\n", + (UINTN)Snp->Mode->State)); + ReturnUnlock (EFI_DEVICE_ERROR); + } + + // Find the LanDriver structure + LanDriver = INSTANCE_FROM_SNP_THIS(Snp); + + // Do a reset if required + if (Reset) { + ZeroMem (&LanDriver->Stats, sizeof(EFI_NETWORK_STATISTICS)); + } + + // Check buffer size + if (*StatSize < sizeof(EFI_NETWORK_STATISTICS)) { + *StatSize = sizeof(EFI_NETWORK_STATISTICS); + ReturnUnlock (EFI_BUFFER_TOO_SMALL); + goto exit_unlock; + } + + // Fill in the statistics + CopyMem(&Statistics, &LanDriver->Stats, sizeof(EFI_NETWORK_STATISTICS)); + Status = EFI_SUCCESS; + + // Restore TPL and return +exit_unlock: + gBS->RestoreTPL (SavedTpl); + return Status; +} + +/* +** UEFI MCastIPtoMAC() function +** +*/ +EFI_STATUS +EFIAPI +SnpMcastIptoMac ( + IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp, + IN BOOLEAN IsIpv6, + IN EFI_IP_ADDRESS *Ip, + OUT EFI_MAC_ADDRESS *McastMac + ) +{ + // Check Snp instance + if (Snp == NULL) { + return EFI_INVALID_PARAMETER; + } + + // Check parameters + if ((McastMac == NULL) || (Ip == NULL)) { + return EFI_INVALID_PARAMETER; + } + + // Make sure MAC address is empty + ZeroMem (McastMac, sizeof(EFI_MAC_ADDRESS)); + + // If we need ipv4 address + if (!IsIpv6) { + // Most significant 25 bits of a multicast HW address are set + McastMac->Addr[0] = 0x01; + McastMac->Addr[1] = 0x00; + McastMac->Addr[2] = 0x5E; + + // Lower 23 bits from ipv4 address + McastMac->Addr[3] = (Ip->v4.Addr[1] & 0x7F); // Clear the ms bit (25th bit of MAC must be 0) + McastMac->Addr[4] = Ip->v4.Addr[2]; + McastMac->Addr[5] = Ip->v4.Addr[3]; + } else { + // Most significant 16 bits of multicast v6 HW address are set + McastMac->Addr[0] = 0x33; + McastMac->Addr[1] = 0x33; + + // lower four octets are taken from ipv6 address + McastMac->Addr[2] = Ip->v6.Addr[8]; + McastMac->Addr[3] = Ip->v6.Addr[9]; + McastMac->Addr[4] = Ip->v6.Addr[10]; + McastMac->Addr[5] = Ip->v6.Addr[11]; + } + + return EFI_SUCCESS; +} + +/* +** UEFI NvData() function +** +*/ +EFI_STATUS +EFIAPI +SnpNvData ( + IN EFI_SIMPLE_NETWORK_PROTOCOL* pobj, + IN BOOLEAN read_write, + IN UINTN offset, + IN UINTN buff_size, + IN OUT VOID *data + ) +{ + DEBUG((EFI_D_ERROR, "LAN91x: Non-volatile storage not supported\n")); + + return EFI_UNSUPPORTED; +} + + +/* +** UEFI GetStatus () function +** +*/ +EFI_STATUS +EFIAPI +SnpGetStatus ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *Snp, + OUT UINT32 *IrqStat OPTIONAL, + OUT VOID **TxBuff OPTIONAL + ) +{ + LAN91X_DRIVER *LanDriver; + EFI_TPL SavedTpl; + EFI_STATUS Status; + BOOLEAN MediaPresent; + UINT8 IstReg; + + // Check preliminaries + if (Snp == NULL) { + return EFI_INVALID_PARAMETER; + } + + // Serialize access to data and registers + SavedTpl = gBS->RaiseTPL (LAN91X_TPL); + + // Check that driver was started and initialised + switch (Snp->Mode->State) { + case EfiSimpleNetworkInitialized: + break; + case EfiSimpleNetworkStarted: + DEBUG((EFI_D_WARN, "LAN91x: Driver not yet initialized\n")); + ReturnUnlock (EFI_DEVICE_ERROR); + case EfiSimpleNetworkStopped: + DEBUG((EFI_D_WARN, "LAN91x: Driver not started\n")); + ReturnUnlock (EFI_NOT_STARTED); + default: + DEBUG((EFI_D_ERROR, "LAN91x: Driver in an invalid state: %u\n", + (UINTN)Snp->Mode->State)); + ReturnUnlock (EFI_DEVICE_ERROR); + } + + // Find the LanDriver structure + LanDriver = INSTANCE_FROM_SNP_THIS(Snp); + + // Arbitrarily set the interrupt status to 0 + if (IrqStat != NULL) { + *IrqStat = 0; + IstReg = ReadIoReg8 (LanDriver, LAN91X_IST); + if ((IstReg & IST_RCV) != 0) { + *IrqStat |= EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT; + } + if ((IstReg & IST_TX) != 0) { + *IrqStat |= EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT; + } + } + + // Pass back the completed buffer address + if (TxBuff != NULL) { + *TxBuff = TxQueRemove (LanDriver); + } + + // Update the media status + MediaPresent = CheckLinkStatus (LanDriver); + if (MediaPresent != Snp->Mode->MediaPresent) { + DEBUG((EFI_D_WARN, "LAN91x: Link %s\n", MediaPresent ? L"up" : L"down")); + } + Snp->Mode->MediaPresent = MediaPresent; + Status = EFI_SUCCESS; + + // Restore TPL and return +exit_unlock: + gBS->RestoreTPL (SavedTpl); + return Status; +} + + +/* +** UEFI Transmit() function +** +*/ +EFI_STATUS +EFIAPI +SnpTransmit ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *Snp, + IN UINTN HdrSize, + IN UINTN BufSize, + IN VOID *BufAddr, + IN EFI_MAC_ADDRESS *SrcAddr OPTIONAL, + IN EFI_MAC_ADDRESS *DstAddr OPTIONAL, + IN UINT16 *Protocol OPTIONAL + ) +{ + LAN91X_DRIVER *LanDriver; + EFI_TPL SavedTpl; + EFI_STATUS Status; + UINT8 *Ptr; + UINTN Len; + UINTN MmuPages; + UINTN Retries; + UINT16 Proto; + UINT8 PktNum; + + // Check preliminaries + if ((Snp == NULL) || (BufAddr == NULL)) { + DEBUG((EFI_D_ERROR, "LAN91x: SnpTransmit(): NULL Snp (%p) or BufAddr (%p)\n", + Snp, BufAddr)); + return EFI_INVALID_PARAMETER; + } + + // Serialize access to data and registers + SavedTpl = gBS->RaiseTPL (LAN91X_TPL); + + // Check that driver was started and initialised + switch (Snp->Mode->State) { + case EfiSimpleNetworkInitialized: + break; + case EfiSimpleNetworkStarted: + DEBUG((EFI_D_WARN, "LAN91x: Driver not yet initialized\n")); + ReturnUnlock (EFI_DEVICE_ERROR); + case EfiSimpleNetworkStopped: + DEBUG((EFI_D_WARN, "LAN91x: Driver not started\n")); + ReturnUnlock (EFI_NOT_STARTED); + default: + DEBUG((EFI_D_ERROR, "LAN91x: Driver in an invalid state: %u\n", + (UINTN)Snp->Mode->State)); + ReturnUnlock (EFI_DEVICE_ERROR); + } + + // Find the LanDriver structure + LanDriver = INSTANCE_FROM_SNP_THIS(Snp); + + // Ensure header is correct size if non-zero + if (HdrSize != 0) { + if (HdrSize != Snp->Mode->MediaHeaderSize) { + DEBUG((EFI_D_ERROR, "LAN91x: SnpTransmit(): Invalid HdrSize %d\n", HdrSize)); + ReturnUnlock (EFI_INVALID_PARAMETER); + } + + if ((DstAddr == NULL) || (Protocol == NULL)) { + DEBUG((EFI_D_ERROR, "LAN91x: SnpTransmit(): NULL DstAddr %p or Protocol %p\n", + DstAddr, Protocol)); + ReturnUnlock (EFI_INVALID_PARAMETER); + } + } + + // Before transmitting check the link status + if (!Snp->Mode->MediaPresent) { + DEBUG((EFI_D_WARN, "LAN91x: SnpTransmit(): Link not ready\n")); + ReturnUnlock (EFI_NOT_READY); + } + + // Calculate the request size in 256-byte "pages" minus 1 + // The 91C111 ignores this, but some older devices need it. + MmuPages = ((BufSize & ~1) + LAN91X_PKT_OVERHEAD - 1) >> 8; + if (MmuPages > 7) { + DEBUG((EFI_D_WARN, "LAN91x: Tx buffer too large (%d bytes)\n", BufSize)); + LanDriver->Stats.TxOversizeFrames += 1; + LanDriver->Stats.TxDroppedFrames += 1; + ReturnUnlock (EFI_BAD_BUFFER_SIZE); + } + + // Request allocation of a transmit buffer + Status = MmuOperation (LanDriver, MMUCR_OP_TX_ALLOC | MmuPages); + if (EFI_ERROR (Status)) { + DEBUG((EFI_D_ERROR, "LAN91x: Tx buffer request failure: %d\n", Status)); + ReturnUnlock (EFI_DEVICE_ERROR); + } + + // Wait for allocation request completion + Retries = LAN91X_MEMORY_ALLOC_POLLS; + while ((ReadIoReg8 (LanDriver, LAN91X_IST) & IST_ALLOC) == 0) { + if (--Retries == 0) { + DEBUG((EFI_D_ERROR, "LAN91x: Tx buffer allocation timeout\n")); + ReturnUnlock (EFI_TIMEOUT); + } + } + + // Check for successful allocation + PktNum = ReadIoReg8 (LanDriver, LAN91X_ARR); + if ((PktNum & ARR_FAILED) != 0) { + DEBUG((EFI_D_ERROR, "LAN91x: Tx buffer allocation failure: %02x\n", PktNum)); + ReturnUnlock (EFI_NOT_READY); + } + PktNum &= ARR_PACKET; + + // Check for the nature of the frame + if (DstAddr->Addr[0] == 0xFF) { + LanDriver->Stats.TxBroadcastFrames += 1; + } else if ((DstAddr->Addr[0] & 0x1) == 1) { + LanDriver->Stats.TxMulticastFrames += 1; + } else { + LanDriver->Stats.TxUnicastFrames += 1; + } + + // Set the Packet Number and Pointer registers + WriteIoReg8 (LanDriver, LAN91X_PNR, PktNum); + WriteIoReg16 (LanDriver, LAN91X_PTR, PTR_AUTO_INCR); + + // Set up mutable buffer information variables + Ptr = BufAddr; + Len = BufSize; + + // Write Status and Byte Count first + WriteIoReg16 (LanDriver, LAN91X_DATA0, 0); + WriteIoReg16 (LanDriver, LAN91X_DATA0, (Len + LAN91X_PKT_OVERHEAD) & BCW_COUNT); + + // This packet may come with a preconfigured Ethernet header. + // If not, we need to construct one from optional parameters. + if (HdrSize) { + + // Write the destination address + WriteIoData (LanDriver, DstAddr, NET_ETHER_ADDR_LEN); + + // Write the Source Address + if (SrcAddr != NULL) { + WriteIoData (LanDriver, SrcAddr, NET_ETHER_ADDR_LEN); + } else { + WriteIoData (LanDriver, &LanDriver->SnpMode.CurrentAddress, NET_ETHER_ADDR_LEN); + } + + // Write the Protocol word + Proto = HTONS (*Protocol); + WriteIoReg16 (LanDriver, LAN91X_DATA0, Proto); + + // Adjust the data start and length + Ptr += sizeof(ETHER_HEAD); + Len -= sizeof(ETHER_HEAD); + } + + // Copy the remainder data buffer, except the odd byte + WriteIoData (LanDriver, Ptr, Len & ~1); + Ptr += Len & ~1; + Len &= 1; + + // Write the Packet Control Word and odd byte + WriteIoReg16 (LanDriver, LAN91X_DATA0, + (Len != 0) ? (PCW_ODD | PCW_CRC | *Ptr) : PCW_CRC); + + // Release the packet for transmission + Status = MmuOperation (LanDriver, MMUCR_OP_TX_PUSH); + if (EFI_ERROR (Status)) { + DEBUG((EFI_D_ERROR, "LAN91x: Tx buffer release failure: %d\n", Status)); + ReturnUnlock (EFI_DEVICE_ERROR); + } + + // Update the Rx statistics + LanDriver->Stats.TxTotalBytes += BufSize; + LanDriver->Stats.TxGoodFrames += 1; + + // Update the Tx Buffer cache + if (!TxQueInsert (LanDriver, BufAddr)) { + DEBUG((EFI_D_WARN, "LAN91x: SnpTransmit(): TxQueue insert failure.\n")); + } + Status = EFI_SUCCESS; + + // Dump the packet header +#if LAN91X_PRINT_PACKET_HEADERS + Ptr = BufAddr; + DEBUG((EFI_D_ERROR, "LAN91X:SnpTransmit()\n")); + DEBUG((EFI_D_ERROR, " HdrSize: %d, SrcAddr: %p, Length: %d, Last byte: %02x\n", + HdrSize, SrcAddr, BufSize, Ptr[BufSize - 1])); + PrintIpDgram ( + (HdrSize == 0) ? (EFI_MAC_ADDRESS *)&Ptr[0] : DstAddr, + (HdrSize == 0) ? (EFI_MAC_ADDRESS *)&Ptr[6] : (SrcAddr != NULL) ? SrcAddr : &LanDriver->SnpMode.CurrentAddress, + (HdrSize == 0) ? (UINT16 *)&Ptr[12] : &Proto, + &Ptr[14] + ); +#endif + + // Restore TPL and return +exit_unlock: + gBS->RestoreTPL (SavedTpl); + return Status; +} + + +/* +** UEFI Receive() function +** +*/ +EFI_STATUS +EFIAPI +SnpReceive ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *Snp, + OUT UINTN *HdrSize OPTIONAL, + IN OUT UINTN *BuffSize, + OUT VOID *Data, + OUT EFI_MAC_ADDRESS *SrcAddr OPTIONAL, + OUT EFI_MAC_ADDRESS *DstAddr OPTIONAL, + OUT UINT16 *Protocol OPTIONAL + ) +{ + EFI_TPL SavedTpl; + EFI_STATUS Status; + LAN91X_DRIVER *LanDriver; + UINT8 *DataPtr; + UINT16 PktStatus; + UINT16 PktLength; + UINT16 PktControl; + UINT8 IstReg; + + // Check preliminaries + if ((Snp == NULL) || (Data == NULL)) { + return EFI_INVALID_PARAMETER; + } + + // Serialize access to data and registers + SavedTpl = gBS->RaiseTPL (LAN91X_TPL); + + // Check that driver was started and initialised + switch (Snp->Mode->State) { + case EfiSimpleNetworkInitialized: + break; + case EfiSimpleNetworkStarted: + DEBUG((EFI_D_WARN, "LAN91x: Driver not yet initialized\n")); + ReturnUnlock (EFI_DEVICE_ERROR); + case EfiSimpleNetworkStopped: + DEBUG((EFI_D_WARN, "LAN91x: Driver not started\n")); + ReturnUnlock (EFI_NOT_STARTED); + default: + DEBUG((EFI_D_ERROR, "LAN91x: Driver in an invalid state: %u\n", + (UINTN)Snp->Mode->State)); + ReturnUnlock (EFI_DEVICE_ERROR); + } + + // Find the LanDriver structure + LanDriver = INSTANCE_FROM_SNP_THIS(Snp); + + // Check for Rx Overrun + IstReg = ReadIoReg8 (LanDriver, LAN91X_IST); + if ((IstReg & IST_RX_OVRN) != 0) { + LanDriver->Stats.RxTotalFrames += 1; + LanDriver->Stats.RxDroppedFrames += 1; + WriteIoReg8 (LanDriver, LAN91X_IST, IST_RX_OVRN); + DEBUG((EFI_D_WARN, "LAN91x: Receiver overrun\n")); + } + + // Check for Rx data available + if ((IstReg & IST_RCV) == 0) { + ReturnUnlock (EFI_NOT_READY); + } + + // Configure the PTR register for reading + WriteIoReg16 (LanDriver, LAN91X_PTR, PTR_RCV | PTR_AUTO_INCR | PTR_READ); + + // Read the Packet Status and Packet Length words + PktStatus = ReadIoReg16 (LanDriver, LAN91X_DATA0); + PktLength = ReadIoReg16 (LanDriver, LAN91X_DATA0) & BCW_COUNT; + + // Check for valid received packet + if ((PktStatus == 0) && (PktLength == 0)) { + DEBUG((EFI_D_WARN, "LAN91x: Received zero-length packet. IST=%04x\n", IstReg)); + ReturnUnlock (EFI_NOT_READY); + } + LanDriver->Stats.RxTotalFrames += 1; + + // Check if we got a CRC error + if ((PktStatus & RX_BAD_CRC) != 0) { + DEBUG((EFI_D_WARN, "LAN91x: Received frame CRC error\n")); + LanDriver->Stats.RxCrcErrorFrames += 1; + LanDriver->Stats.RxDroppedFrames += 1; + Status = EFI_DEVICE_ERROR; + goto exit_release; + } + + // Check if we got a too-short frame + if ((PktStatus & RX_TOO_SHORT) != 0) { + DEBUG((EFI_D_WARN, "LAN91x: Received frame too short (%d bytes)\n", PktLength)); + LanDriver->Stats.RxUndersizeFrames += 1; + LanDriver->Stats.RxDroppedFrames += 1; + Status = EFI_DEVICE_ERROR; + goto exit_release; + } + + // Check if we got a too-long frame + if ((PktStatus & RX_TOO_LONG) != 0) { + DEBUG((EFI_D_WARN, "LAN91x: Received frame too long (%d bytes)\n", PktLength)); + LanDriver->Stats.RxOversizeFrames += 1; + LanDriver->Stats.RxDroppedFrames += 1; + Status = EFI_DEVICE_ERROR; + goto exit_release; + } + + // Check if we got an alignment error + if ((PktStatus & RX_ALGN_ERR) != 0) { + DEBUG((EFI_D_WARN, "LAN91x: Received frame alignment error\n")); + // Don't seem to keep track of these specifically + LanDriver->Stats.RxDroppedFrames += 1; + Status = EFI_DEVICE_ERROR; + goto exit_release; + } + + // Classify the received fram + if ((PktStatus & RX_MULTICAST) != 0) { + LanDriver->Stats.RxMulticastFrames += 1; + } else if ((PktStatus & RX_BROADCAST) != 0) { + LanDriver->Stats.RxBroadcastFrames += 1; + } else { + LanDriver->Stats.RxUnicastFrames += 1; + } + + // Calculate the received packet data length + PktLength -= LAN91X_PKT_OVERHEAD; + if ((PktStatus & RX_ODD_FRAME) != 0) { + PktLength += 1; + } + + // Check buffer size + if (*BuffSize < PktLength) { + DEBUG((EFI_D_WARN, "LAN91x: Receive buffer too small for packet (%d < %d)\n", + *BuffSize, PktLength)); + *BuffSize = PktLength; + Status = EFI_BUFFER_TOO_SMALL; + goto exit_release; + } + + // Transfer the data bytes + DataPtr = Data; + ReadIoData (LanDriver, DataPtr, PktLength & ~0x0001); + + // Read the PktControl and Odd Byte from the FIFO + PktControl = ReadIoReg16 (LanDriver, LAN91X_DATA0); + if ((PktControl & PCW_ODD) != 0) { + DataPtr[PktLength - 1] = PktControl & PCW_ODD_BYTE; + } + + // Update buffer size + *BuffSize = PktLength; + + if (HdrSize != NULL) { + *HdrSize = LanDriver->SnpMode.MediaHeaderSize; + } + + // Extract the destination address + if (DstAddr != NULL) { + CopyMem (DstAddr, &DataPtr[0], NET_ETHER_ADDR_LEN); + } + + // Get the source address + if (SrcAddr != NULL) { + CopyMem (SrcAddr, &DataPtr[6], NET_ETHER_ADDR_LEN); + } + + // Get the protocol + if (Protocol != NULL) { + *Protocol = NTOHS (*(UINT16*)(&DataPtr[12])); + } + + // Update the Rx statistics + LanDriver->Stats.RxTotalBytes += PktLength; + LanDriver->Stats.RxGoodFrames += 1; + Status = EFI_SUCCESS; + +#if LAN91X_PRINT_PACKET_HEADERS + // Dump the packet header + DEBUG((EFI_D_ERROR, "LAN91X:SnpReceive()\n")); + DEBUG((EFI_D_ERROR, " HdrSize: %p, SrcAddr: %p, DstAddr: %p, Protocol: %p\n", + HdrSize, SrcAddr, DstAddr, Protocol)); + DEBUG((EFI_D_ERROR, " Length: %d, Last byte: %02x\n", PktLength, DataPtr[PktLength - 1])); + PrintIpDgram (&DataPtr[0], &DataPtr[6], &DataPtr[12], &DataPtr[14]); +#endif + + // Release the FIFO buffer +exit_release: + MmuOperation (LanDriver, MMUCR_OP_RX_POP_REL); + + // Restore TPL and return +exit_unlock: + gBS->RestoreTPL (SavedTpl); + return Status; +} + + +/*------------------ Driver Execution Environment main entry point ------------------*/ + +/* +** Entry point for the LAN91x driver +** +*/ +EFI_STATUS +Lan91xDxeEntry ( + IN EFI_HANDLE Handle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + LAN91X_DRIVER *LanDriver; + EFI_SIMPLE_NETWORK_PROTOCOL *Snp; + EFI_SIMPLE_NETWORK_MODE *SnpMode; + LAN91X_DEVICE_PATH *Lan91xPath; + + // The PcdLan91xDxeBaseAddress PCD must be defined + ASSERT(PcdGet32 (PcdLan91xDxeBaseAddress) != 0); + + // Allocate Resources + LanDriver = AllocateZeroPool (sizeof(LAN91X_DRIVER)); + Lan91xPath = AllocateCopyPool (sizeof(LAN91X_DEVICE_PATH), &Lan91xPathTemplate); + + // Initialize I/O Space access info + LanDriver->IoBase = PcdGet32 (PcdLan91xDxeBaseAddress); + LanDriver->PhyAd = LAN91X_NO_PHY; + LanDriver->BankSel = 0xff; + + // Initialize pointers + Snp = &(LanDriver->Snp); + SnpMode = &(LanDriver->SnpMode); + Snp->Mode = SnpMode; + + // Set the signature of the LAN Driver structure + LanDriver->Signature = LAN91X_SIGNATURE; + + // Probe the device + Status = Probe (LanDriver); + if (EFI_ERROR(Status)) { + DEBUG((EFI_D_ERROR, "LAN91x:Lan91xDxeEntry(): Probe failed with status %d\n", Status)); + return Status; + } + +#ifdef LAN91X_PRINT_REGISTERS + PrintIoRegisters (LanDriver); + PrintPhyRegisters (LanDriver); +#endif + + // Assign fields and func pointers + Snp->Revision = EFI_SIMPLE_NETWORK_PROTOCOL_REVISION; + Snp->WaitForPacket = NULL; + Snp->Initialize = SnpInitialize; + Snp->Start = SnpStart; + Snp->Stop = SnpStop; + Snp->Reset = SnpReset; + Snp->Shutdown = SnpShutdown; + Snp->ReceiveFilters = SnpReceiveFilters; + Snp->StationAddress = SnpStationAddress; + Snp->Statistics = SnpStatistics; + Snp->MCastIpToMac = SnpMcastIptoMac; + Snp->NvData = SnpNvData; + Snp->GetStatus = SnpGetStatus; + Snp->Transmit = SnpTransmit; + Snp->Receive = SnpReceive; + + // Fill in simple network mode structure + SnpMode->State = EfiSimpleNetworkStopped; + SnpMode->HwAddressSize = NET_ETHER_ADDR_LEN; // HW address is 6 bytes + SnpMode->MediaHeaderSize = sizeof(ETHER_HEAD); // Size of an Ethernet header + SnpMode->MaxPacketSize = EFI_PAGE_SIZE; // Ethernet Frame (with VLAN tag +4 bytes) + + // Supported receive filters + 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; + + // Initially-enabled receive filters + SnpMode->ReceiveFilterSetting = EFI_SIMPLE_NETWORK_RECEIVE_UNICAST | + EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST | + EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST; + + // LAN91x has 64bit hash table. We can filter an infinite MACs, but + // higher-level software must filter out any hash collisions. + SnpMode->MaxMCastFilterCount = MAX_MCAST_FILTER_CNT; + SnpMode->MCastFilterCount = 0; + ZeroMem (&SnpMode->MCastFilter, MAX_MCAST_FILTER_CNT * sizeof(EFI_MAC_ADDRESS)); + + // Set the interface type (1: Ethernet or 6: IEEE 802 Networks) + SnpMode->IfType = NET_IFTYPE_ETHERNET; + + // Mac address is changeable + SnpMode->MacAddressChangeable = TRUE; + + // We can only transmit one packet at a time + SnpMode->MultipleTxSupported = FALSE; + + // MediaPresent checks for cable connection and partner link + SnpMode->MediaPresentSupported = TRUE; + SnpMode->MediaPresent = FALSE; + + // Set broadcast address + SetMem (&SnpMode->BroadcastAddress, sizeof (EFI_MAC_ADDRESS), 0xFF); + + // Assign fields for device path + Lan91xPath->Lan91x.MacAddress = SnpMode->PermanentAddress; + Lan91xPath->Lan91x.IfType = SnpMode->IfType; + + // Initialise the protocol + Status = gBS->InstallMultipleProtocolInterfaces ( + &LanDriver->ControllerHandle, + &gEfiSimpleNetworkProtocolGuid, Snp, + &gEfiDevicePathProtocolGuid, Lan91xPath, + NULL + ); + + // Say what the status of loading the protocol structure is + if (EFI_ERROR(Status)) { + FreePool (LanDriver); + } + + return Status; +} diff --git a/ArmPlatformPkg/Drivers/LAN91xDxe/LAN91xDxe.inf b/ArmPlatformPkg/Drivers/LAN91xDxe/LAN91xDxe.inf new file mode 100644 index 000000000..c7ef43ba2 --- /dev/null +++ b/ArmPlatformPkg/Drivers/LAN91xDxe/LAN91xDxe.inf @@ -0,0 +1,58 @@ +#/** @file +# INF file for the SMSC LAN91x series Network Controller Driver. +# +# Copyright (c) 2013 Linaro.org +# +# Derived from the LAN9118 driver. Original sources +# Copyright (c) 2012-2013, 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. +# +#**/ + +[Defines] + INF_VERSION = 0x00010006 + BASE_NAME = LAN91xDxe + FILE_GUID = 5c12ea2f-9897-48af-8138-25f4ce6ff8d6 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 0.1 + ENTRY_POINT = Lan91xDxeEntry + +[Sources.common] + LAN91xDxe.c + LAN91xDxeHw.h + +[Packages] + ArmPlatformPkg/ArmPlatformPkg.dec + NetworkPkg/NetworkPkg.dec + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + +[LibraryClasses] + BaseLib + UefiLib + NetLib + UefiDriverEntryPoint + BaseMemoryLib + ArmLib + IoLib + TimerLib + DevicePathLib + +[Protocols] + gEfiSimpleNetworkProtocolGuid + gEfiMetronomeArchProtocolGuid + gEfiPxeBaseCodeProtocolGuid + gEfiDevicePathProtocolGuid + +[FixedPcd] + gArmPlatformTokenSpaceGuid.PcdLan91xDxeBaseAddress + +[Depex] + TRUE diff --git a/ArmPlatformPkg/Drivers/LAN91xDxe/LAN91xDxeHw.h b/ArmPlatformPkg/Drivers/LAN91xDxe/LAN91xDxeHw.h new file mode 100644 index 000000000..9274ba072 --- /dev/null +++ b/ArmPlatformPkg/Drivers/LAN91xDxe/LAN91xDxeHw.h @@ -0,0 +1,278 @@ +/** @file +* SMSC LAN91x series Network Controller Driver. +* +* Copyright (c) 2013 Linaro.org +* +* 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. +* +**/ + +#ifndef __LAN91XDXEHW_H__ +#define __LAN91XDXEHW_H__ + +#include + +#define MakeRegister(Bank, Offset) (((Bank) << 8) | (Offset)) +#define RegisterToBank(Register) (((Register) >> 8) & 0x07) +#define RegisterToOffset(Register) ((Register) & 0x0f) + +/*--------------------------------------------------------------------------------------------------------------------- + + SMSC LAN91x Registers + +---------------------------------------------------------------------------------------------------------------------*/ +#define LAN91X_BANK_OFFSET 0xe // Bank Select Register (all banks) + +#define LAN91X_TCR MakeRegister (0, 0x0) // Transmit Control Register +#define LAN91X_EPHSR MakeRegister (0, 0x2) // EPH Status Register +#define LAN91X_RCR MakeRegister (0, 0x4) // Receive Control Register +#define LAN91X_ECR MakeRegister (0, 0x6) // Counter Register +#define LAN91X_MIR MakeRegister (0, 0x8) // Memory Information Register +#define LAN91X_RPCR MakeRegister (0, 0xa) // Receive/Phy Control Register + +#define LAN91X_CR MakeRegister (1, 0x0) // Configuration Register +#define LAN91X_BAR MakeRegister (1, 0x2) // Base Address Register +#define LAN91X_IAR0 MakeRegister (1, 0x4) // Individual Address Register 0 +#define LAN91X_IAR1 MakeRegister (1, 0x5) // Individual Address Register 1 +#define LAN91X_IAR2 MakeRegister (1, 0x6) // Individual Address Register 2 +#define LAN91X_IAR3 MakeRegister (1, 0x7) // Individual Address Register 3 +#define LAN91X_IAR4 MakeRegister (1, 0x8) // Individual Address Register 4 +#define LAN91X_IAR5 MakeRegister (1, 0x9) // Individual Address Register 5 +#define LAN91X_GPR MakeRegister (1, 0xa) // General Purpose Register +#define LAN91X_CTR MakeRegister (1, 0xc) // Control Register + +#define LAN91X_MMUCR MakeRegister (2, 0x0) // MMU Command Register +#define LAN91X_PNR MakeRegister (2, 0x2) // Packet Number Register +#define LAN91X_ARR MakeRegister (2, 0x3) // Allocation Result Register +#define LAN91X_FIFO MakeRegister (2, 0x4) // FIFO Ports Register +#define LAN91X_PTR MakeRegister (2, 0x6) // Pointer Register +#define LAN91X_DATA0 MakeRegister (2, 0x8) // Data Register 0 +#define LAN91X_DATA1 MakeRegister (2, 0x9) // Data Register 1 +#define LAN91X_DATA2 MakeRegister (2, 0xa) // Data Register 2 +#define LAN91X_DATA3 MakeRegister (2, 0xb) // Data Register 3 +#define LAN91X_IST MakeRegister (2, 0xc) // Interrupt Status Register +#define LAN91X_MSK MakeRegister (2, 0xd) // Interrupt Mask Register + +#define LAN91X_MT0 MakeRegister (3, 0x0) // Multicast Table Register 0 +#define LAN91X_MT1 MakeRegister (3, 0x1) // Multicast Table Register 1 +#define LAN91X_MT2 MakeRegister (3, 0x2) // Multicast Table Register 2 +#define LAN91X_MT3 MakeRegister (3, 0x3) // Multicast Table Register 3 +#define LAN91X_MT4 MakeRegister (3, 0x4) // Multicast Table Register 4 +#define LAN91X_MT5 MakeRegister (3, 0x5) // Multicast Table Register 5 +#define LAN91X_MT6 MakeRegister (3, 0x6) // Multicast Table Register 6 +#define LAN91X_MT7 MakeRegister (3, 0x7) // Multicast Table Register 7 +#define LAN91X_MGMT MakeRegister (3, 0x8) // Management Interface Register +#define LAN91X_REV MakeRegister (3, 0xa) // Revision Register +#define LAN91X_RCV MakeRegister (3, 0xc) // RCV Register + +// Transmit Control Register Bits +#define TCR_TXENA BIT0 +#define TCR_LOOP BIT1 +#define TCR_FORCOL BIT2 +#define TCR_PAD_EN BIT7 +#define TCR_NOCRC BIT8 +#define TCR_MON_CSN BIT10 +#define TCR_FDUPLX BIT11 +#define TCR_STP_SQET BIT12 +#define TCR_EPH_LOOP BIT13 +#define TCR_SWFDUP BIT15 + +#define TCR_DEFAULT (TCR_TXENA | TCR_PAD_EN) +#define TCR_CLEAR 0x0 + +// EPH Status Register Bits +#define EPHSR_TX_SUC BIT0 +#define EPHSR_SNGLCOL BIT1 +#define EPHSR_MULCOL BIT2 +#define EPHSR_LTX_MULT BIT3 +#define EPHSR_16COL BIT4 +#define EPHSR_SQET BIT5 +#define EPHSR_LTX_BRD BIT6 +#define EPHSR_TX_DEFR BIT7 +#define EPHSR_LATCOL BIT9 +#define EPHSR_LOST_CARR BIT10 +#define EPHSR_EXC_DEF BIT11 +#define EPHSR_CTR_ROL BIT12 +#define EPHSR_LINK_OK BIT14 + +// Receive Control Register Bits +#define RCR_RX_ABORT BIT0 +#define RCR_PRMS BIT1 +#define RCR_ALMUL BIT2 +#define RCR_RXEN BIT8 +#define RCR_STRIP_CRC BIT9 +#define RCR_ABORT_ENB BIT13 +#define RCR_FILT_CAR BIT14 +#define RCR_SOFT_RST BIT15 + +#define RCR_DEFAULT (RCR_STRIP_CRC | RCR_RXEN) +#define RCR_CLEAR 0x0 + +// Receive/Phy Control Register Bits +#define RPCR_LS0B BIT2 +#define RPCR_LS1B BIT3 +#define RPCR_LS2B BIT4 +#define RPCR_LS0A BIT5 +#define RPCR_LS1A BIT6 +#define RPCR_LS2A BIT7 +#define RPCR_ANEG BIT11 +#define RPCR_DPLX BIT12 +#define RPCR_SPEED BIT13 + +// Configuration Register Bits +#define CR_EXT_PHY BIT9 +#define CR_GPCNTRL BIT10 +#define CR_NO_WAIT BIT12 +#define CR_EPH_POWER_EN BIT15 + +#define CR_DEFAULT (CR_EPH_POWER_EN | CR_NO_WAIT) + +// Control Register Bits +#define CTR_STORE BIT0 +#define CTR_RELOAD BIT1 +#define CTR_EEPROM_SEL BIT2 +#define CTR_TE_ENABLE BIT5 +#define CTR_CR_ENABLE BIT6 +#define CTR_LE_ENABLE BIT7 +#define CTR_AUTO_REL BIT11 +#define CTR_RCV_BAD BIT14 + +#define CTR_RESERVED (BIT12 | BIT9 | BIT4) +#define CTR_DEFAULT (CTR_RESERVED | CTR_AUTO_REL) + +// MMU Command Register Bits +#define MMUCR_BUSY BIT0 + +// MMU Command Register Operaction Codes +#define MMUCR_OP_NOOP (0 << 5) // No operation +#define MMUCR_OP_TX_ALLOC (1 << 5) // Allocate memory for TX +#define MMUCR_OP_RESET_MMU (2 << 5) // Reset MMU to initial state +#define MMUCR_OP_RX_POP (3 << 5) // Remove frame from top of RX FIFO +#define MMUCR_OP_RX_POP_REL (4 << 5) // Remove and release frame from top of RX FIFO +#define MMUCR_OP_RX_REL (5 << 5) // Release specific RX frame +#define MMUCR_OP_TX_PUSH (6 << 5) // Enqueue packet number into TX FIFO +#define MMUCR_OP_TX_RESET (7 << 5) // Reset TX FIFOs + +// Packet Number Register Bits +#define PNR_PACKET (0x3f) + +// Allocation Result Register Bits +#define ARR_PACKET (0x3f) +#define ARR_FAILED BIT7 + +// FIFO Ports Register Bits +#define FIFO_TX_PACKET (0x003f) +#define FIFO_TEMPTY BIT7 +#define FIFO_RX_PACKET (0x3f00) +#define FIFO_REMPTY BIT15 + +// Pointer Register Bits +#define PTR_POINTER (0x07ff) +#define PTR_NOT_EMPTY BIT11 +#define PTR_READ BIT13 +#define PTR_AUTO_INCR BIT14 +#define PTR_RCV BIT15 + +// Interupt Status and Mask Register Bits +#define IST_RCV BIT0 +#define IST_TX BIT1 +#define IST_TX_EMPTY BIT2 +#define IST_ALLOC BIT3 +#define IST_RX_OVRN BIT4 +#define IST_EPH BIT5 +#define IST_MD BIT7 + +// Management Interface +#define MGMT_MDO BIT0 +#define MGMT_MDI BIT1 +#define MGMT_MCLK BIT2 +#define MGMT_MDOE BIT3 +#define MGMT_MSK_CRS100 BIT14 + +// RCV Register +#define RCV_MBO (0x1f) +#define RCV_RCV_DISCRD BIT7 + +// Packet RX Status word bits +#define RX_MULTICAST BIT0 +#define RX_HASH (0x7e) +#define RX_TOO_SHORT BIT10 +#define RX_TOO_LONG BIT11 +#define RX_ODD_FRAME BIT12 +#define RX_BAD_CRC BIT13 +#define RX_BROADCAST BIT14 +#define RX_ALGN_ERR BIT15 + +// Packet Byte Count word bits +#define BCW_COUNT (0x7fe) + +// Packet Control Word bits +#define PCW_ODD_BYTE (0x00ff) +#define PCW_CRC BIT12 +#define PCW_ODD BIT13 + +/*--------------------------------------------------------------------------------------------------------------------- + + SMSC PHY Registers + + Most of these should be common, as there is + documented STANDARD for PHY registers! + +---------------------------------------------------------------------------------------------------------------------*/ +// +// PHY Register Numbers +// +#define PHY_INDEX_BASIC_CTRL 0 +#define PHY_INDEX_BASIC_STATUS 1 +#define PHY_INDEX_ID1 2 +#define PHY_INDEX_ID2 3 +#define PHY_INDEX_AUTO_NEG_ADVERT 4 +#define PHY_INDEX_AUTO_NEG_LINK_ABILITY 5 + +#define PHY_INDEX_CONFIG1 16 +#define PHY_INDEX_CONFIG2 17 +#define PHY_INDEX_STATUS_OUTPUT 18 +#define PHY_INDEX_MASK 19 + + +// PHY control register bits +#define PHYCR_COLL_TEST BIT7 // Collision test enable +#define PHYCR_DUPLEX_MODE BIT8 // Set Duplex Mode +#define PHYCR_RST_AUTO BIT9 // Restart Auto-Negotiation of Link abilities +#define PHYCR_PD BIT11 // Power-Down switch +#define PHYCR_AUTO_EN BIT12 // Auto-Negotiation Enable +#define PHYCR_SPEED_SEL BIT13 // Link Speed Selection +#define PHYCR_LOOPBK BIT14 // Set loopback mode +#define PHYCR_RESET BIT15 // Do a PHY reset + +// PHY status register bits +#define PHYSTS_EXT_CAP BIT0 // Extended Capabilities Register capability +#define PHYSTS_JABBER BIT1 // Jabber condition detected +#define PHYSTS_LINK_STS BIT2 // Link Status +#define PHYSTS_AUTO_CAP BIT3 // Auto-Negotiation Capability +#define PHYSTS_REMOTE_FAULT BIT4 // Remote fault detected +#define PHYSTS_AUTO_COMP BIT5 // Auto-Negotiation Completed +#define PHYSTS_10BASET_HDPLX BIT11 // 10Mbps Half-Duplex ability +#define PHYSTS_10BASET_FDPLX BIT12 // 10Mbps Full-Duplex ability +#define PHYSTS_100BASETX_HDPLX BIT13 // 100Mbps Half-Duplex ability +#define PHYSTS_100BASETX_FDPLX BIT14 // 100Mbps Full-Duplex ability +#define PHYSTS_100BASE_T4 BIT15 // Base T4 ability + +// PHY Auto-Negotiation advertisement +#define PHYANA_SEL_MASK ((UINT32)0x1F) // Link type selector +#define PHYANA_CSMA BIT0 // Advertise CSMA capability +#define PHYANA_10BASET BIT5 // Advertise 10BASET capability +#define PHYANA_10BASETFD BIT6 // Advertise 10BASET Full duplex capability +#define PHYANA_100BASETX BIT7 // Advertise 100BASETX capability +#define PHYANA_100BASETXFD BIT8 // Advertise 100 BASETX Full duplex capability +#define PHYANA_100BASET4 BIT9 // Advertise 100 BASETX Full duplex capability +#define PHYANA_PAUSE_OP_MASK (3 << 10) // Advertise PAUSE frame capability +#define PHYANA_REMOTE_FAULT BIT13 // Remote fault detected + +#endif /* __LAN91XDXEHW_H__ */ -- cgit v1.2.3 From efacd45e63d04fd0126014a965e4c23fcf5bf6df Mon Sep 17 00:00:00 2001 From: "Reece R. Pollack" Date: Thu, 26 Sep 2013 19:50:03 -0400 Subject: LAN9118: Fix RELEASE build and some uninit variables The restructuring of the synchronization introduced or exposed some uninitialized variables. This patch fixes these. Also, the RELEASE build produced some warnings about an unused function used only from within DEBUG() statements. This patch conditionalizes this debug-only function on the same define used to control the expansion of the DEBUG macro. Signed-off-by: Reece R. Pollack --- ArmPlatformPkg/Drivers/LAN9118Dxe/LAN9118Dxe.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/ArmPlatformPkg/Drivers/LAN9118Dxe/LAN9118Dxe.c b/ArmPlatformPkg/Drivers/LAN9118Dxe/LAN9118Dxe.c index 010a8e473..92391323a 100644 --- a/ArmPlatformPkg/Drivers/LAN9118Dxe/LAN9118Dxe.c +++ b/ArmPlatformPkg/Drivers/LAN9118Dxe/LAN9118Dxe.c @@ -223,6 +223,7 @@ GenEtherCrc32 ( return ReverseBits (Remainder); } +#ifndef MDEPKG_NDEBUG STATIC CONST CHAR16 *Mac2Str (EFI_MAC_ADDRESS *Mac) { static CHAR16 MacStr[18]; @@ -237,6 +238,7 @@ STATIC CONST CHAR16 *Mac2Str (EFI_MAC_ADDRESS *Mac) Mac->Addr[3], Mac->Addr[4], Mac->Addr[5]); return MacStr; } +#endif // Function to read from MAC indirect registers UINT32 @@ -1772,6 +1774,7 @@ SnpStationAddress ( IndirectMACWrite32 (INDIRECT_MAC_INDEX_ADDRL, (UINT32)((UINT32)NewMac->Addr[0]) | ((UINT32)NewMac->Addr[1] << 8) | ((UINT32)NewMac->Addr[2] << 16) | ((UINT32)NewMac->Addr[3] << 24)); IndirectMACWrite32 (INDIRECT_MAC_INDEX_ADDRH, (UINT32)((((UINT32)NewMac->Addr[4]) | ((UINT32)NewMac->Addr[5] << 8)) & 0xFFFF)); } + Status = EFI_SUCCESS; // Restore TPL and return exit_unlock: @@ -1815,6 +1818,7 @@ SnpStatistics ( // Serialize access to data and registers SavedTpl = gBS->RaiseTPL (LAN9118_TPL); + LanDriver = INSTANCE_FROM_SNP_THIS(Snp); // Check that driver was started and initialised if (Snp->Mode->State == EfiSimpleNetworkStarted) { @@ -2080,6 +2084,8 @@ SnpTransmit ( // Serialize access to data and registers SavedTpl = gBS->RaiseTPL (LAN9118_TPL); + LanDriver = INSTANCE_FROM_SNP_THIS(Snp); + TxCacheIndex = (-1); if (Snp->Mode->State != EfiSimpleNetworkInitialized) { ReturnUnlock (EFI_NOT_STARTED); @@ -2101,9 +2107,6 @@ SnpTransmit ( ReturnUnlock (EFI_NOT_READY); } - LanDriver = INSTANCE_FROM_SNP_THIS(Snp); - TxCacheIndex = (-1); - // Find a free entry in the TxCache array for (TxCacheIndex = LAN9118_TX_CACHE_DEPTH - 1; TxCacheIndex >= 0; --TxCacheIndex) { if (LanDriver->TxCache[TxCacheIndex] == NULL) { -- cgit v1.2.3