diff --git a/ArmPlatformPkg/ArmPlatformPkg.dec b/ArmPlatformPkg/ArmPlatformPkg.dec
index 3358225..2c4f888 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 cb04012..fe0604b 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 0000000..9239132
--- /dev/null
+++ b/ArmPlatformPkg/Drivers/LAN9118Dxe/LAN9118Dxe.c
@@ -0,0 +1,2592 @@
+/** @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);
+}
+
+#ifndef MDEPKG_NDEBUG
+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;
+}
+#endif
+
+// 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));
+  }
+  Status = EFI_SUCCESS;
+
+  // 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);
+  LanDriver = INSTANCE_FROM_SNP_THIS(Snp);
+
+  // 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);
+  LanDriver = INSTANCE_FROM_SNP_THIS(Snp);
+  TxCacheIndex = (-1);
+
+  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);
+  }
+
+  // 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 0000000..232f502
--- /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 0000000..f622d0b
--- /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__ */
