summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorReece R. Pollack <reece.pollack@linaro.org>2013-09-25 23:41:09 -0400
committerReece R. Pollack <reece.pollack@linaro.org>2013-09-25 23:41:09 -0400
commitff92e9bc27ad83cbf03c9917ccb833134ec1b407 (patch)
tree6f385f699fcf4f66efd0afcede61bb3cd31aeed0
parentb742bf9a7117e77bffb3b344353c882f3d84556f (diff)
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 <reece.pollack@linaro.org>
-rw-r--r--ArmPlatformPkg/ArmPlatformPkg.dec5
-rw-r--r--ArmPlatformPkg/ArmVExpressPkg/ArmVExpress.dsc.inc1
-rw-r--r--ArmPlatformPkg/Drivers/LAN9118Dxe/LAN9118Dxe.c2589
-rw-r--r--ArmPlatformPkg/Drivers/LAN9118Dxe/LAN9118Dxe.inf55
-rw-r--r--ArmPlatformPkg/Drivers/LAN9118Dxe/LAN9118DxeHw.h325
5 files changed, 2975 insertions, 0 deletions
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 <Uefi.h>
+#include <Uefi/UefiSpec.h>
+#include <Base.h>
+
+// Protocols used by this driver
+#include <Protocol/SimpleNetwork.h>
+#include <Protocol/ComponentName2.h>
+#include <Protocol/PxeBaseCode.h>
+#include <Protocol/DevicePath.h>
+
+// Libraries used by this driver
+#include <Library/UefiLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/IoLib.h>
+#include <Library/PcdLib.h>
+#include <Library/NetLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/PrintLib.h>
+
+#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"<null>";
+ }
+
+ 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__ */